]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
ITS#5695
[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-2008 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 /* X.509 PMI ldapSyntaxes */
61 /* FIXME: need to create temporary OIDs under OpenLDAP's arc;
62  * these are currently hijacked
63  *
64  *      1.3.6.1.4.1.4203.666            OpenLDAP
65  *      1.3.6.1.4.1.4203.666.11         self-contained works
66  *      1.3.6.1.4.1.4203.666.11.10      X.509 PMI
67  *      1.3.6.1.4.1.4203.666.11.10.2    X.509 PMI ldapSyntaxes
68  *      1.3.6.1.4.1.4203.666.11.10.2.1  AttributeCertificate (supported)
69  *      1.3.6.1.4.1.4203.666.11.10.2.2  AttributeCertificateExactAssertion (supported)
70  *      1.3.6.1.4.1.4203.666.11.10.2.3  AttributeCertificateAssertion (not supported)
71  *      1.3.6.1.4.1.4203.666.11.10.2.4  AttCertPath (X-SUBST'ed right now in pmi.schema)
72  *      1.3.6.1.4.1.4203.666.11.10.2.5  PolicySyntax (X-SUBST'ed right now in pmi.schema)
73  *      1.3.6.1.4.1.4203.666.11.10.2.6  RoleSyntax (X-SUBST'ed right now in pmi.schema)
74  */
75 #if 0 /* from <draft-ietf-pkix-ldap-schema-02.txt> (expired) */
76 #define attributeCertificateSyntaxOID                   "1.2.826.0.1.3344810.7.5"
77 #define attributeCertificateExactAssertionSyntaxOID     "1.2.826.0.1.3344810.7.6"
78 #define attributeCertificateAssertionSyntaxOID          "1.2.826.0.1.3344810.7.7"
79 #else /* from OpenLDAP's experimental oid arc */
80 #define X509_PMI_SyntaxOID                              "1.3.6.1.4.1.4203.666.11.10.2"
81 #define attributeCertificateSyntaxOID                   X509_PMI_SyntaxOID ".1"
82 #define attributeCertificateExactAssertionSyntaxOID     X509_PMI_SyntaxOID ".2"
83 #define attributeCertificateAssertionSyntaxOID          X509_PMI_SyntaxOID ".3"
84 #endif
85
86 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
87 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
88 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
89 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
90
91 unsigned int index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
92 unsigned int index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
93         SLAP_INDEX_INTLEN_DEFAULT );
94
95 ldap_pvt_thread_mutex_t ad_undef_mutex;
96 ldap_pvt_thread_mutex_t oc_undef_mutex;
97
98 static int
99 generalizedTimeValidate(
100         Syntax *syntax,
101         struct berval *in );
102
103 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
104 static int
105 utcTimeValidate(
106         Syntax *syntax,
107         struct berval *in );
108 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
109
110 static int
111 inValidate(
112         Syntax *syntax,
113         struct berval *in )
114 {
115         /* no value allowed */
116         return LDAP_INVALID_SYNTAX;
117 }
118
119 static int
120 blobValidate(
121         Syntax *syntax,
122         struct berval *in )
123 {
124         /* any value allowed */
125         return LDAP_SUCCESS;
126 }
127
128 #define berValidate blobValidate
129
130 static int
131 sequenceValidate(
132         Syntax *syntax,
133         struct berval *in )
134 {
135         if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
136         if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
137
138         return LDAP_SUCCESS;
139 }
140
141 /* X.509 related stuff */
142
143 enum {
144         SLAP_X509_V1            = 0,
145         SLAP_X509_V2            = 1,
146         SLAP_X509_V3            = 2
147 };
148
149 enum {
150         SLAP_TAG_UTCTIME                = 0x17U,
151         SLAP_TAG_GENERALIZEDTIME        = 0x18U
152 };
153
154
155 #define SLAP_X509_OPTION        (LBER_CLASS_CONTEXT|LBER_CONSTRUCTED)
156
157 enum {
158         SLAP_X509_OPT_C_VERSION         = SLAP_X509_OPTION + 0,
159         SLAP_X509_OPT_C_ISSUERUNIQUEID  = SLAP_X509_OPTION + 1,
160         SLAP_X509_OPT_C_SUBJECTUNIQUEID = SLAP_X509_OPTION + 2,
161         SLAP_X509_OPT_C_EXTENSIONS      = SLAP_X509_OPTION + 3
162 };
163
164 enum {
165         SLAP_X509_OPT_CL_CRLEXTENSIONS  = SLAP_X509_OPTION + 0
166 };
167
168 /*
169 GeneralName ::= CHOICE {
170   otherName                 [0] INSTANCE OF OTHER-NAME,
171   rfc822Name                [1] IA5String,
172   dNSName                   [2] IA5String,
173   x400Address               [3] ORAddress,
174   directoryName             [4] Name,
175   ediPartyName              [5] EDIPartyName,
176   uniformResourceIdentifier [6] IA5String,
177   iPAddress                 [7] OCTET STRING,
178   registeredID              [8] OBJECT IDENTIFIER }
179 */
180 enum {
181         SLAP_X509_GN_OTHERNAME          = SLAP_X509_OPTION + 0,
182         SLAP_X509_GN_RFC822NAME         = SLAP_X509_OPTION + 1,
183         SLAP_X509_GN_DNSNAME            = SLAP_X509_OPTION + 2,
184         SLAP_X509_GN_X400ADDRESS        = SLAP_X509_OPTION + 3,
185         SLAP_X509_GN_DIRECTORYNAME      = SLAP_X509_OPTION + 4,
186         SLAP_X509_GN_EDIPARTYNAME       = SLAP_X509_OPTION + 5,
187         SLAP_X509_GN_URI                = SLAP_X509_OPTION + 6,
188         SLAP_X509_GN_IPADDRESS          = SLAP_X509_OPTION + 7,
189         SLAP_X509_GN_REGISTEREDID       = SLAP_X509_OPTION + 8
190 };
191
192 /* X.509 PMI related stuff */
193 enum {
194         SLAP_X509AC_V1          = 0,
195         SLAP_X509AC_V2          = 1
196 };
197
198 enum {
199         SLAP_X509AC_ISSUER      = SLAP_X509_OPTION + 0
200 };
201
202 /* X.509 certificate validation */
203 static int
204 certificateValidate( Syntax *syntax, struct berval *in )
205 {
206         BerElementBuffer berbuf;
207         BerElement *ber = (BerElement *)&berbuf;
208         ber_tag_t tag;
209         ber_len_t len;
210         ber_int_t version = SLAP_X509_V1;
211
212         ber_init2( ber, in, LBER_USE_DER );
213         tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
214         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
215         tag = ber_skip_tag( ber, &len );        /* Sequence */
216         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
217         tag = ber_peek_tag( ber, &len );
218         /* Optional version */
219         if ( tag == SLAP_X509_OPT_C_VERSION ) {
220                 tag = ber_skip_tag( ber, &len );
221                 tag = ber_get_int( ber, &version );
222                 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
223         }
224         /* NOTE: don't try to parse Serial, because it might be longer
225          * than sizeof(ber_int_t); deferred to certificateExactNormalize() */
226         tag = ber_skip_tag( ber, &len );        /* Serial */
227         if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
228         ber_skip_data( ber, len );
229         tag = ber_skip_tag( ber, &len );        /* Signature Algorithm */
230         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
231         ber_skip_data( ber, len );
232         tag = ber_skip_tag( ber, &len );        /* Issuer DN */
233         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
234         ber_skip_data( ber, len );
235         tag = ber_skip_tag( ber, &len );        /* Validity */
236         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
237         ber_skip_data( ber, len );
238         tag = ber_skip_tag( ber, &len );        /* Subject DN */
239         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
240         ber_skip_data( ber, len );
241         tag = ber_skip_tag( ber, &len );        /* Subject PublicKeyInfo */
242         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
243         ber_skip_data( ber, len );
244         tag = ber_skip_tag( ber, &len );
245         if ( tag == SLAP_X509_OPT_C_ISSUERUNIQUEID ) {  /* issuerUniqueID */
246                 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
247                 ber_skip_data( ber, len );
248                 tag = ber_skip_tag( ber, &len );
249         }
250         if ( tag == SLAP_X509_OPT_C_SUBJECTUNIQUEID ) { /* subjectUniqueID */
251                 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
252                 ber_skip_data( ber, len );
253                 tag = ber_skip_tag( ber, &len );
254         }
255         if ( tag == SLAP_X509_OPT_C_EXTENSIONS ) {      /* Extensions */
256                 if ( version < SLAP_X509_V3 ) return LDAP_INVALID_SYNTAX;
257                 tag = ber_skip_tag( ber, &len );
258                 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
259                 ber_skip_data( ber, len );
260                 tag = ber_skip_tag( ber, &len );
261         }
262         /* signatureAlgorithm */
263         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
264         ber_skip_data( ber, len );
265         tag = ber_skip_tag( ber, &len );
266         /* Signature */
267         if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX; 
268         ber_skip_data( ber, len );
269         tag = ber_skip_tag( ber, &len );
270         /* Must be at end now */
271         if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
272         return LDAP_SUCCESS;
273 }
274
275 /* X.509 certificate list validation */
276 static int
277 certificateListValidate( Syntax *syntax, struct berval *in )
278 {
279         BerElementBuffer berbuf;
280         BerElement *ber = (BerElement *)&berbuf;
281         ber_tag_t tag;
282         ber_len_t len;
283         ber_int_t version = SLAP_X509_V1;
284
285         ber_init2( ber, in, LBER_USE_DER );
286         tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
287         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
288         tag = ber_skip_tag( ber, &len );        /* Sequence */
289         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
290         tag = ber_peek_tag( ber, &len );
291         /* Optional version */
292         if ( tag == LBER_INTEGER ) {
293                 tag = ber_get_int( ber, &version );
294                 assert( tag == LBER_INTEGER );
295                 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
296         }
297         tag = ber_skip_tag( ber, &len );        /* Signature Algorithm */
298         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
299         ber_skip_data( ber, len );
300         tag = ber_skip_tag( ber, &len );        /* Issuer DN */
301         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
302         ber_skip_data( ber, len );
303         tag = ber_skip_tag( ber, &len );        /* thisUpdate */
304         /* Time is a CHOICE { UTCTime, GeneralizedTime } */
305         if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
306         ber_skip_data( ber, len );
307         /* Optional nextUpdate */
308         tag = ber_skip_tag( ber, &len );
309         if ( tag == SLAP_TAG_UTCTIME || tag == SLAP_TAG_GENERALIZEDTIME ) {
310                 ber_skip_data( ber, len );
311                 tag = ber_skip_tag( ber, &len );
312         }
313         /* revokedCertificates - Sequence of Sequence, Optional */
314         if ( tag == LBER_SEQUENCE ) {
315                 ber_len_t seqlen;
316                 if ( ber_peek_tag( ber, &seqlen ) == LBER_SEQUENCE ) {
317                         /* Should NOT be empty */
318                         ber_skip_data( ber, len );
319                         tag = ber_skip_tag( ber, &len );
320                 }
321         }
322         /* Optional Extensions */
323         if ( tag == SLAP_X509_OPT_CL_CRLEXTENSIONS ) { /* ? */
324                 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
325                 tag = ber_skip_tag( ber, &len );
326                 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
327                 ber_skip_data( ber, len );
328                 tag = ber_skip_tag( ber, &len );
329         }
330         /* signatureAlgorithm */
331         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
332         ber_skip_data( ber, len );
333         tag = ber_skip_tag( ber, &len );
334         /* Signature */
335         if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX; 
336         ber_skip_data( ber, len );
337         tag = ber_skip_tag( ber, &len );
338         /* Must be at end now */
339         if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
340         return LDAP_SUCCESS;
341 }
342
343 /* X.509 PMI Attribute Certificate Validate */
344 static int
345 attributeCertificateValidate( Syntax *syntax, struct berval *in )
346 {
347         BerElementBuffer berbuf;
348         BerElement *ber = (BerElement *)&berbuf;
349         ber_tag_t tag;
350         ber_len_t len;
351         ber_int_t version;
352         int cont = 0;
353
354         ber_init2( ber, in, LBER_USE_DER );
355         
356         tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
357         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
358
359         tag = ber_skip_tag( ber, &len );        /* Sequence */
360         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
361
362         tag = ber_peek_tag( ber, &len );        /* Version */
363         if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
364         tag = ber_get_int( ber, &version );     /* X.509 only allows v2 */
365         if ( version != SLAP_X509AC_V2 ) return LDAP_INVALID_SYNTAX;
366
367         tag = ber_skip_tag( ber, &len );        /* Holder */
368         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
369         ber_skip_data( ber, len );
370
371         tag = ber_skip_tag( ber, &len );        /* Issuer */
372         if ( tag != SLAP_X509AC_ISSUER ) return LDAP_INVALID_SYNTAX;
373         ber_skip_data( ber, len );
374
375         tag = ber_skip_tag( ber, &len );        /* Signature */
376         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
377         ber_skip_data( ber, len );
378
379         tag = ber_skip_tag( ber, &len );        /* Serial number */
380         if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
381         ber_skip_data( ber, len );
382
383         tag = ber_skip_tag( ber, &len );        /* AttCertValidityPeriod */
384         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
385         ber_skip_data( ber, len );
386
387         tag = ber_skip_tag( ber, &len );        /* Attributes */
388         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
389         ber_skip_data( ber, len );
390
391         ber_peek_tag( ber, &len );
392
393         if ( tag == LBER_BITSTRING ) {  /* issuerUniqueID */
394                 tag = ber_skip_tag( ber, &len );
395                 ber_skip_data( ber, len );
396                 tag = ber_peek_tag( ber, &len );
397         }
398
399         if ( tag == LBER_SEQUENCE ) {   /* extensions or signatureAlgorithm */
400                 tag = ber_skip_tag( ber, &len );
401                 ber_skip_data( ber, len );
402                 cont++;
403                 tag = ber_peek_tag( ber, &len );
404         }
405
406         if ( tag == LBER_SEQUENCE ) {   /* signatureAlgorithm */
407                 tag = ber_skip_tag( ber, &len );
408                 ber_skip_data( ber, len );
409                 cont++;
410                 tag = ber_peek_tag( ber, &len );
411         }
412
413         if ( tag == LBER_BITSTRING ) {  /* Signature */
414                 tag = ber_skip_tag( ber, &len );
415                 ber_skip_data( ber, len );
416                 cont++;
417                 tag = ber_peek_tag( ber, &len );
418         }
419
420         /* Must be at end now */
421         if ( len != 0 || tag != LBER_DEFAULT || cont < 2 ) return LDAP_INVALID_SYNTAX;
422
423         return LDAP_SUCCESS;
424 }
425
426 int
427 octetStringMatch(
428         int *matchp,
429         slap_mask_t flags,
430         Syntax *syntax,
431         MatchingRule *mr,
432         struct berval *value,
433         void *assertedValue )
434 {
435         struct berval *asserted = (struct berval *) assertedValue;
436         int match = value->bv_len - asserted->bv_len;
437
438         if( match == 0 ) {
439                 match = memcmp( value->bv_val, asserted->bv_val, value->bv_len );
440         }
441
442         *matchp = match;
443         return LDAP_SUCCESS;
444 }
445
446 int
447 octetStringOrderingMatch(
448         int *matchp,
449         slap_mask_t flags,
450         Syntax *syntax,
451         MatchingRule *mr,
452         struct berval *value,
453         void *assertedValue )
454 {
455         struct berval *asserted = (struct berval *) assertedValue;
456         ber_len_t v_len  = value->bv_len;
457         ber_len_t av_len = asserted->bv_len;
458
459         int match = memcmp( value->bv_val, asserted->bv_val,
460                 (v_len < av_len ? v_len : av_len) );
461
462         if( match == 0 ) match = v_len - av_len;
463
464         *matchp = match;
465         return LDAP_SUCCESS;
466 }
467
468 static void
469 hashPreset(
470         HASH_CONTEXT *HASHcontext,
471         struct berval *prefix,
472         char pre,
473         Syntax *syntax,
474         MatchingRule *mr)
475 {
476         HASH_Init(HASHcontext);
477         if(prefix && prefix->bv_len > 0) {
478                 HASH_Update(HASHcontext,
479                         (unsigned char *)prefix->bv_val, prefix->bv_len);
480         }
481         if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
482         HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
483         HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
484         return;
485 }
486
487 static void
488 hashIter(
489         HASH_CONTEXT *HASHcontext,
490         unsigned char *HASHdigest,
491         unsigned char *value,
492         int len)
493 {
494         HASH_CONTEXT ctx = *HASHcontext;
495         HASH_Update( &ctx, value, len );
496         HASH_Final( HASHdigest, &ctx );
497 }
498
499 /* Index generation function */
500 int octetStringIndexer(
501         slap_mask_t use,
502         slap_mask_t flags,
503         Syntax *syntax,
504         MatchingRule *mr,
505         struct berval *prefix,
506         BerVarray values,
507         BerVarray *keysp,
508         void *ctx )
509 {
510         int i;
511         size_t slen, mlen;
512         BerVarray keys;
513         HASH_CONTEXT HASHcontext;
514         unsigned char HASHdigest[HASH_BYTES];
515         struct berval digest;
516         digest.bv_val = (char *)HASHdigest;
517         digest.bv_len = sizeof(HASHdigest);
518
519         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
520                 /* just count them */
521         }
522
523         /* we should have at least one value at this point */
524         assert( i > 0 );
525
526         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
527
528         slen = syntax->ssyn_oidlen;
529         mlen = mr->smr_oidlen;
530
531         hashPreset( &HASHcontext, prefix, 0, syntax, mr);
532         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
533                 hashIter( &HASHcontext, HASHdigest,
534                         (unsigned char *)values[i].bv_val, values[i].bv_len );
535                 ber_dupbv_x( &keys[i], &digest, ctx );
536         }
537
538         BER_BVZERO( &keys[i] );
539
540         *keysp = keys;
541
542         return LDAP_SUCCESS;
543 }
544
545 /* Index generation function */
546 int octetStringFilter(
547         slap_mask_t use,
548         slap_mask_t flags,
549         Syntax *syntax,
550         MatchingRule *mr,
551         struct berval *prefix,
552         void * assertedValue,
553         BerVarray *keysp,
554         void *ctx )
555 {
556         size_t slen, mlen;
557         BerVarray keys;
558         HASH_CONTEXT HASHcontext;
559         unsigned char HASHdigest[HASH_BYTES];
560         struct berval *value = (struct berval *) assertedValue;
561         struct berval digest;
562         digest.bv_val = (char *)HASHdigest;
563         digest.bv_len = sizeof(HASHdigest);
564
565         slen = syntax->ssyn_oidlen;
566         mlen = mr->smr_oidlen;
567
568         keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
569
570         hashPreset( &HASHcontext, prefix, 0, syntax, mr );
571         hashIter( &HASHcontext, HASHdigest,
572                 (unsigned char *)value->bv_val, value->bv_len );
573
574         ber_dupbv_x( keys, &digest, ctx );
575         BER_BVZERO( &keys[1] );
576
577         *keysp = keys;
578
579         return LDAP_SUCCESS;
580 }
581
582 static int
583 octetStringSubstringsMatch(
584         int *matchp,
585         slap_mask_t flags,
586         Syntax *syntax,
587         MatchingRule *mr,
588         struct berval *value,
589         void *assertedValue )
590 {
591         int match = 0;
592         SubstringsAssertion *sub = assertedValue;
593         struct berval left = *value;
594         int i;
595         ber_len_t inlen = 0;
596
597         /* Add up asserted input length */
598         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
599                 inlen += sub->sa_initial.bv_len;
600         }
601         if ( sub->sa_any ) {
602                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
603                         inlen += sub->sa_any[i].bv_len;
604                 }
605         }
606         if ( !BER_BVISNULL( &sub->sa_final ) ) {
607                 inlen += sub->sa_final.bv_len;
608         }
609
610         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
611                 if ( inlen > left.bv_len ) {
612                         match = 1;
613                         goto done;
614                 }
615
616                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
617                         sub->sa_initial.bv_len );
618
619                 if ( match != 0 ) {
620                         goto done;
621                 }
622
623                 left.bv_val += sub->sa_initial.bv_len;
624                 left.bv_len -= sub->sa_initial.bv_len;
625                 inlen -= sub->sa_initial.bv_len;
626         }
627
628         if ( !BER_BVISNULL( &sub->sa_final ) ) {
629                 if ( inlen > left.bv_len ) {
630                         match = 1;
631                         goto done;
632                 }
633
634                 match = memcmp( sub->sa_final.bv_val,
635                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
636                         sub->sa_final.bv_len );
637
638                 if ( match != 0 ) {
639                         goto done;
640                 }
641
642                 left.bv_len -= sub->sa_final.bv_len;
643                 inlen -= sub->sa_final.bv_len;
644         }
645
646         if ( sub->sa_any ) {
647                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
648                         ber_len_t idx;
649                         char *p;
650
651 retry:
652                         if ( inlen > left.bv_len ) {
653                                 /* not enough length */
654                                 match = 1;
655                                 goto done;
656                         }
657
658                         if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
659                                 continue;
660                         }
661
662                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
663
664                         if( p == NULL ) {
665                                 match = 1;
666                                 goto done;
667                         }
668
669                         idx = p - left.bv_val;
670
671                         if ( idx >= left.bv_len ) {
672                                 /* this shouldn't happen */
673                                 return LDAP_OTHER;
674                         }
675
676                         left.bv_val = p;
677                         left.bv_len -= idx;
678
679                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
680                                 /* not enough left */
681                                 match = 1;
682                                 goto done;
683                         }
684
685                         match = memcmp( left.bv_val,
686                                 sub->sa_any[i].bv_val,
687                                 sub->sa_any[i].bv_len );
688
689                         if ( match != 0 ) {
690                                 left.bv_val++;
691                                 left.bv_len--;
692                                 goto retry;
693                         }
694
695                         left.bv_val += sub->sa_any[i].bv_len;
696                         left.bv_len -= sub->sa_any[i].bv_len;
697                         inlen -= sub->sa_any[i].bv_len;
698                 }
699         }
700
701 done:
702         *matchp = match;
703         return LDAP_SUCCESS;
704 }
705
706 /* Substrings Index generation function */
707 static int
708 octetStringSubstringsIndexer(
709         slap_mask_t use,
710         slap_mask_t flags,
711         Syntax *syntax,
712         MatchingRule *mr,
713         struct berval *prefix,
714         BerVarray values,
715         BerVarray *keysp,
716         void *ctx )
717 {
718         ber_len_t i, nkeys;
719         size_t slen, mlen;
720         BerVarray keys;
721
722         HASH_CONTEXT HCany, HCini, HCfin;
723         unsigned char HASHdigest[HASH_BYTES];
724         struct berval digest;
725         digest.bv_val = (char *)HASHdigest;
726         digest.bv_len = sizeof(HASHdigest);
727
728         nkeys = 0;
729
730         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
731                 /* count number of indices to generate */
732                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
733                         if( values[i].bv_len >= index_substr_if_maxlen ) {
734                                 nkeys += index_substr_if_maxlen -
735                                         (index_substr_if_minlen - 1);
736                         } else if( values[i].bv_len >= index_substr_if_minlen ) {
737                                 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
738                         }
739                 }
740
741                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
742                         if( values[i].bv_len >= index_substr_any_len ) {
743                                 nkeys += values[i].bv_len - (index_substr_any_len - 1);
744                         }
745                 }
746
747                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
748                         if( values[i].bv_len >= index_substr_if_maxlen ) {
749                                 nkeys += index_substr_if_maxlen -
750                                         (index_substr_if_minlen - 1);
751                         } else if( values[i].bv_len >= index_substr_if_minlen ) {
752                                 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
753                         }
754                 }
755         }
756
757         if( nkeys == 0 ) {
758                 /* no keys to generate */
759                 *keysp = NULL;
760                 return LDAP_SUCCESS;
761         }
762
763         keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
764
765         slen = syntax->ssyn_oidlen;
766         mlen = mr->smr_oidlen;
767
768         if ( flags & SLAP_INDEX_SUBSTR_ANY )
769                 hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
770         if( flags & SLAP_INDEX_SUBSTR_INITIAL )
771                 hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
772         if( flags & SLAP_INDEX_SUBSTR_FINAL )
773                 hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
774
775         nkeys = 0;
776         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
777                 ber_len_t j,max;
778
779                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
780                         ( values[i].bv_len >= index_substr_any_len ) )
781                 {
782                         max = values[i].bv_len - (index_substr_any_len - 1);
783
784                         for( j=0; j<max; j++ ) {
785                                 hashIter( &HCany, HASHdigest,
786                                         (unsigned char *)&values[i].bv_val[j],
787                                         index_substr_any_len );
788                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
789                         }
790                 }
791
792                 /* skip if too short */ 
793                 if( values[i].bv_len < index_substr_if_minlen ) continue;
794
795                 max = index_substr_if_maxlen < values[i].bv_len
796                         ? index_substr_if_maxlen : values[i].bv_len;
797
798                 for( j=index_substr_if_minlen; j<=max; j++ ) {
799
800                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
801                                 hashIter( &HCini, HASHdigest,
802                                         (unsigned char *)values[i].bv_val, j );
803                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
804                         }
805
806                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
807                                 hashIter( &HCfin, HASHdigest,
808                                         (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
809                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
810                         }
811
812                 }
813         }
814
815         if( nkeys > 0 ) {
816                 BER_BVZERO( &keys[nkeys] );
817                 *keysp = keys;
818         } else {
819                 ch_free( keys );
820                 *keysp = NULL;
821         }
822
823         return LDAP_SUCCESS;
824 }
825
826 static int
827 octetStringSubstringsFilter (
828         slap_mask_t use,
829         slap_mask_t flags,
830         Syntax *syntax,
831         MatchingRule *mr,
832         struct berval *prefix,
833         void * assertedValue,
834         BerVarray *keysp,
835         void *ctx)
836 {
837         SubstringsAssertion *sa;
838         char pre;
839         ber_len_t nkeys = 0;
840         size_t slen, mlen, klen;
841         BerVarray keys;
842         HASH_CONTEXT HASHcontext;
843         unsigned char HASHdigest[HASH_BYTES];
844         struct berval *value;
845         struct berval digest;
846
847         sa = (SubstringsAssertion *) assertedValue;
848
849         if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
850                 !BER_BVISNULL( &sa->sa_initial ) &&
851                 sa->sa_initial.bv_len >= index_substr_if_minlen )
852         {
853                 nkeys++;
854                 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
855                         ( flags & SLAP_INDEX_SUBSTR_ANY ))
856                 {
857                         nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
858                 }
859         }
860
861         if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
862                 ber_len_t i;
863                 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
864                         if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
865                                 /* don't bother accounting with stepping */
866                                 nkeys += sa->sa_any[i].bv_len -
867                                         ( index_substr_any_len - 1 );
868                         }
869                 }
870         }
871
872         if( flags & SLAP_INDEX_SUBSTR_FINAL &&
873                 !BER_BVISNULL( &sa->sa_final ) &&
874                 sa->sa_final.bv_len >= index_substr_if_minlen )
875         {
876                 nkeys++;
877                 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
878                         ( flags & SLAP_INDEX_SUBSTR_ANY ))
879                 {
880                         nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
881                 }
882         }
883
884         if( nkeys == 0 ) {
885                 *keysp = NULL;
886                 return LDAP_SUCCESS;
887         }
888
889         digest.bv_val = (char *)HASHdigest;
890         digest.bv_len = sizeof(HASHdigest);
891
892         slen = syntax->ssyn_oidlen;
893         mlen = mr->smr_oidlen;
894
895         keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
896         nkeys = 0;
897
898         if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
899                 !BER_BVISNULL( &sa->sa_initial ) &&
900                 sa->sa_initial.bv_len >= index_substr_if_minlen )
901         {
902                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
903                 value = &sa->sa_initial;
904
905                 klen = index_substr_if_maxlen < value->bv_len
906                         ? index_substr_if_maxlen : value->bv_len;
907
908                 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
909                 hashIter( &HASHcontext, HASHdigest,
910                         (unsigned char *)value->bv_val, klen );
911                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
912
913                 /* If initial is too long and we have subany indexed, use it
914                  * to match the excess...
915                  */
916                 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
917                 {
918                         ber_len_t j;
919                         pre = SLAP_INDEX_SUBSTR_PREFIX;
920                         hashPreset( &HASHcontext, prefix, pre, syntax, mr);
921                         for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
922                         {
923                                 hashIter( &HASHcontext, HASHdigest,
924                                         (unsigned char *)&value->bv_val[j], index_substr_any_len );
925                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
926                         }
927                 }
928         }
929
930         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
931                 ber_len_t i, j;
932                 pre = SLAP_INDEX_SUBSTR_PREFIX;
933                 klen = index_substr_any_len;
934
935                 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
936                         if( sa->sa_any[i].bv_len < index_substr_any_len ) {
937                                 continue;
938                         }
939
940                         value = &sa->sa_any[i];
941
942                         hashPreset( &HASHcontext, prefix, pre, syntax, mr);
943                         for(j=0;
944                                 j <= value->bv_len - index_substr_any_len;
945                                 j += index_substr_any_step )
946                         {
947                                 hashIter( &HASHcontext, HASHdigest,
948                                         (unsigned char *)&value->bv_val[j], klen ); 
949                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
950                         }
951                 }
952         }
953
954         if( flags & SLAP_INDEX_SUBSTR_FINAL &&
955                 !BER_BVISNULL( &sa->sa_final ) &&
956                 sa->sa_final.bv_len >= index_substr_if_minlen )
957         {
958                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
959                 value = &sa->sa_final;
960
961                 klen = index_substr_if_maxlen < value->bv_len
962                         ? index_substr_if_maxlen : value->bv_len;
963
964                 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
965                 hashIter( &HASHcontext, HASHdigest,
966                         (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
967                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
968
969                 /* If final is too long and we have subany indexed, use it
970                  * to match the excess...
971                  */
972                 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
973                 {
974                         ber_len_t j;
975                         pre = SLAP_INDEX_SUBSTR_PREFIX;
976                         hashPreset( &HASHcontext, prefix, pre, syntax, mr);
977                         for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
978                         {
979                                 hashIter( &HASHcontext, HASHdigest,
980                                         (unsigned char *)&value->bv_val[j], index_substr_any_len );
981                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
982                         }
983                 }
984         }
985
986         if( nkeys > 0 ) {
987                 BER_BVZERO( &keys[nkeys] );
988                 *keysp = keys;
989         } else {
990                 ch_free( keys );
991                 *keysp = NULL;
992         }
993
994         return LDAP_SUCCESS;
995 }
996
997 static int
998 bitStringValidate(
999         Syntax *syntax,
1000         struct berval *in )
1001 {
1002         ber_len_t i;
1003
1004         /* very unforgiving validation, requires no normalization
1005          * before simplistic matching
1006          */
1007         if( in->bv_len < 3 ) {
1008                 return LDAP_INVALID_SYNTAX;
1009         }
1010
1011         /* RFC 4517 Section 3.3.2 Bit String:
1012          *      BitString    = SQUOTE *binary-digit SQUOTE "B"
1013          *      binary-digit = "0" / "1"
1014          *
1015          * where SQUOTE [RFC4512] is
1016          *      SQUOTE  = %x27 ; single quote ("'")
1017          *
1018          * Example: '0101111101'B
1019          */
1020         
1021         if( in->bv_val[0] != '\'' ||
1022                 in->bv_val[in->bv_len - 2] != '\'' ||
1023                 in->bv_val[in->bv_len - 1] != 'B' )
1024         {
1025                 return LDAP_INVALID_SYNTAX;
1026         }
1027
1028         for( i = in->bv_len - 3; i > 0; i-- ) {
1029                 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
1030                         return LDAP_INVALID_SYNTAX;
1031                 }
1032         }
1033
1034         return LDAP_SUCCESS;
1035 }
1036
1037 /*
1038  * Syntaxes from RFC 4517
1039  *
1040
1041 3.3.2.  Bit String
1042
1043    A value of the Bit String syntax is a sequence of binary digits.  The
1044    LDAP-specific encoding of a value of this syntax is defined by the
1045    following ABNF:
1046
1047       BitString    = SQUOTE *binary-digit SQUOTE "B"
1048
1049       binary-digit = "0" / "1"
1050
1051    The <SQUOTE> rule is defined in [MODELS].
1052
1053       Example:
1054          '0101111101'B
1055
1056    The LDAP definition for the Bit String syntax is:
1057
1058       ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
1059
1060    This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
1061
1062    ...
1063
1064 3.3.21.  Name and Optional UID
1065
1066    A value of the Name and Optional UID syntax is the distinguished name
1067    [MODELS] of an entity optionally accompanied by a unique identifier
1068    that serves to differentiate the entity from others with an identical
1069    distinguished name.
1070
1071    The LDAP-specific encoding of a value of this syntax is defined by
1072    the following ABNF:
1073
1074        NameAndOptionalUID = distinguishedName [ SHARP BitString ]
1075
1076    The <BitString> rule is defined in Section 3.3.2.  The
1077    <distinguishedName> rule is defined in [LDAPDN].  The <SHARP> rule is
1078    defined in [MODELS].
1079
1080    Note that although the '#' character may occur in the string
1081    representation of a distinguished name, no additional escaping of
1082    this character is performed when a <distinguishedName> is encoded in
1083    a <NameAndOptionalUID>.
1084
1085       Example:
1086          1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
1087
1088    The LDAP definition for the Name and Optional UID syntax is:
1089
1090       ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
1091
1092    This syntax corresponds to the NameAndOptionalUID ASN.1 type from
1093    [X.520].
1094
1095  *
1096  * RFC 4512 says:
1097  *
1098
1099 1.4. Common ABNF Productions
1100
1101   ...
1102       SHARP   = %x23 ; octothorpe (or sharp sign) ("#")
1103   ...
1104       SQUOTE  = %x27 ; single quote ("'")
1105   ...
1106       
1107  *
1108  * Note: normalization strips any leading "0"s, unless the
1109  * bit string is exactly "'0'B", so the normalized example,
1110  * in slapd, would result in
1111  * 
1112  * 1.3.6.1.4.1.1466.0=#04024869,o=test,c=gb#'101'B
1113  * 
1114  * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
1115  * be escaped except when at the beginning of a value, the
1116  * definition of Name and Optional UID appears to be flawed,
1117  * because there is no clear means to determine whether the
1118  * UID part is present or not.
1119  *
1120  * Example:
1121  *
1122  *      cn=Someone,dc=example,dc=com#'1'B
1123  *
1124  * could be either a NameAndOptionalUID with trailing UID, i.e.
1125  *
1126  *      DN = "cn=Someone,dc=example,dc=com"
1127  *      UID = "'1'B"
1128  * 
1129  * or a NameAndOptionalUID with no trailing UID, and the AVA
1130  * in the last RDN made of
1131  *
1132  *      attributeType = dc 
1133  *      attributeValue = com#'1'B
1134  *
1135  * in fact "com#'1'B" is a valid IA5 string.
1136  *
1137  * As a consequence, current slapd code assumes that the
1138  * presence of portions of a BitString at the end of the string 
1139  * representation of a NameAndOptionalUID means a BitString
1140  * is expected, and cause an error otherwise.  This is quite
1141  * arbitrary, and might change in the future.
1142  */
1143
1144
1145 static int
1146 nameUIDValidate(
1147         Syntax *syntax,
1148         struct berval *in )
1149 {
1150         int rc;
1151         struct berval dn, uid;
1152
1153         if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
1154
1155         ber_dupbv( &dn, in );
1156         if( !dn.bv_val ) return LDAP_OTHER;
1157
1158         /* if there's a "#", try bitStringValidate()... */
1159         uid.bv_val = strrchr( dn.bv_val, '#' );
1160         if ( !BER_BVISNULL( &uid ) ) {
1161                 uid.bv_val++;
1162                 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
1163
1164                 rc = bitStringValidate( NULL, &uid );
1165                 if ( rc == LDAP_SUCCESS ) {
1166                         /* in case of success, trim the UID,
1167                          * otherwise treat it as part of the DN */
1168                         dn.bv_len -= uid.bv_len + 1;
1169                         uid.bv_val[-1] = '\0';
1170                 }
1171         }
1172
1173         rc = dnValidate( NULL, &dn );
1174
1175         ber_memfree( dn.bv_val );
1176         return rc;
1177 }
1178
1179 int
1180 nameUIDPretty(
1181         Syntax *syntax,
1182         struct berval *val,
1183         struct berval *out,
1184         void *ctx )
1185 {
1186         assert( val != NULL );
1187         assert( out != NULL );
1188
1189
1190         Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
1191
1192         if( BER_BVISEMPTY( val ) ) {
1193                 ber_dupbv_x( out, val, ctx );
1194
1195         } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
1196                 return LDAP_INVALID_SYNTAX;
1197
1198         } else {
1199                 int             rc;
1200                 struct berval   dnval = *val;
1201                 struct berval   uidval = BER_BVNULL;
1202
1203                 uidval.bv_val = strrchr( val->bv_val, '#' );
1204                 if ( !BER_BVISNULL( &uidval ) ) {
1205                         uidval.bv_val++;
1206                         uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
1207
1208                         rc = bitStringValidate( NULL, &uidval );
1209
1210                         if ( rc == LDAP_SUCCESS ) {
1211                                 ber_dupbv_x( &dnval, val, ctx );
1212                                 dnval.bv_len -= uidval.bv_len + 1;
1213                                 dnval.bv_val[dnval.bv_len] = '\0';
1214
1215                         } else {
1216                                 BER_BVZERO( &uidval );
1217                         }
1218                 }
1219
1220                 rc = dnPretty( syntax, &dnval, out, ctx );
1221                 if ( dnval.bv_val != val->bv_val ) {
1222                         slap_sl_free( dnval.bv_val, ctx );
1223                 }
1224                 if( rc != LDAP_SUCCESS ) {
1225                         return rc;
1226                 }
1227
1228                 if( !BER_BVISNULL( &uidval ) ) {
1229                         int     i, c, got1;
1230                         char    *tmp;
1231
1232                         tmp = slap_sl_realloc( out->bv_val, out->bv_len 
1233                                 + STRLENOF( "#" ) + uidval.bv_len + 1,
1234                                 ctx );
1235                         if( tmp == NULL ) {
1236                                 ber_memfree_x( out->bv_val, ctx );
1237                                 return LDAP_OTHER;
1238                         }
1239                         out->bv_val = tmp;
1240                         out->bv_val[out->bv_len++] = '#';
1241                         out->bv_val[out->bv_len++] = '\'';
1242
1243                         got1 = uidval.bv_len < sizeof("'0'B"); 
1244                         for( i = 1; i < uidval.bv_len - 2; i++ ) {
1245                                 c = uidval.bv_val[i];
1246                                 switch(c) {
1247                                         case '0':
1248                                                 if( got1 ) out->bv_val[out->bv_len++] = c;
1249                                                 break;
1250                                         case '1':
1251                                                 got1 = 1;
1252                                                 out->bv_val[out->bv_len++] = c;
1253                                                 break;
1254                                 }
1255                         }
1256
1257                         out->bv_val[out->bv_len++] = '\'';
1258                         out->bv_val[out->bv_len++] = 'B';
1259                         out->bv_val[out->bv_len] = '\0';
1260                 }
1261         }
1262
1263         Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1264
1265         return LDAP_SUCCESS;
1266 }
1267
1268 static int
1269 uniqueMemberNormalize(
1270         slap_mask_t usage,
1271         Syntax *syntax,
1272         MatchingRule *mr,
1273         struct berval *val,
1274         struct berval *normalized,
1275         void *ctx )
1276 {
1277         struct berval out;
1278         int rc;
1279
1280         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1281
1282         ber_dupbv_x( &out, val, ctx );
1283         if ( BER_BVISEMPTY( &out ) ) {
1284                 *normalized = out;
1285
1286         } else {
1287                 struct berval uid = BER_BVNULL;
1288
1289                 uid.bv_val = strrchr( out.bv_val, '#' );
1290                 if ( !BER_BVISNULL( &uid ) ) {
1291                         uid.bv_val++;
1292                         uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1293
1294                         rc = bitStringValidate( NULL, &uid );
1295                         if ( rc == LDAP_SUCCESS ) {
1296                                 uid.bv_val[-1] = '\0';
1297                                 out.bv_len -= uid.bv_len + 1;
1298                         } else {
1299                                 BER_BVZERO( &uid );
1300                         }
1301                 }
1302
1303                 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1304
1305                 if( rc != LDAP_SUCCESS ) {
1306                         slap_sl_free( out.bv_val, ctx );
1307                         return LDAP_INVALID_SYNTAX;
1308                 }
1309
1310                 if( !BER_BVISNULL( &uid ) ) {
1311                         char    *tmp;
1312
1313                         tmp = ch_realloc( normalized->bv_val,
1314                                 normalized->bv_len + uid.bv_len
1315                                 + STRLENOF("#") + 1 );
1316                         if ( tmp == NULL ) {
1317                                 ber_memfree_x( normalized->bv_val, ctx );
1318                                 return LDAP_OTHER;
1319                         }
1320
1321                         normalized->bv_val = tmp;
1322
1323                         /* insert the separator */
1324                         normalized->bv_val[normalized->bv_len++] = '#';
1325
1326                         /* append the UID */
1327                         AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1328                                 uid.bv_val, uid.bv_len );
1329                         normalized->bv_len += uid.bv_len;
1330
1331                         /* terminate */
1332                         normalized->bv_val[normalized->bv_len] = '\0';
1333                 }
1334
1335                 slap_sl_free( out.bv_val, ctx );
1336         }
1337
1338         return LDAP_SUCCESS;
1339 }
1340
1341 static int
1342 uniqueMemberMatch(
1343         int *matchp,
1344         slap_mask_t flags,
1345         Syntax *syntax,
1346         MatchingRule *mr,
1347         struct berval *value,
1348         void *assertedValue )
1349 {
1350         int match;
1351         struct berval *asserted = (struct berval *) assertedValue;
1352         struct berval assertedDN = *asserted;
1353         struct berval assertedUID = BER_BVNULL;
1354         struct berval valueDN = *value;
1355         struct berval valueUID = BER_BVNULL;
1356         int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1357
1358         if ( !BER_BVISEMPTY( asserted ) ) {
1359                 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1360                 if ( !BER_BVISNULL( &assertedUID ) ) {
1361                         assertedUID.bv_val++;
1362                         assertedUID.bv_len = assertedDN.bv_len
1363                                 - ( assertedUID.bv_val - assertedDN.bv_val );
1364
1365                         if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1366                                 assertedDN.bv_len -= assertedUID.bv_len + 1;
1367
1368                         } else {
1369                                 BER_BVZERO( &assertedUID );
1370                         }
1371                 }
1372         }
1373
1374         if ( !BER_BVISEMPTY( value ) ) {
1375
1376                 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1377                 if ( !BER_BVISNULL( &valueUID ) ) {
1378                         valueUID.bv_val++;
1379                         valueUID.bv_len = valueDN.bv_len
1380                                 - ( valueUID.bv_val - valueDN.bv_val );
1381
1382                         if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1383                                 valueDN.bv_len -= valueUID.bv_len + 1;
1384
1385                         } else {
1386                                 BER_BVZERO( &valueUID );
1387                         }
1388                 }
1389         }
1390
1391         if( valueUID.bv_len && assertedUID.bv_len ) {
1392                 match = valueUID.bv_len - assertedUID.bv_len;
1393                 if ( match ) {
1394                         *matchp = match;
1395                         return LDAP_SUCCESS;
1396                 }
1397
1398                 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1399                 if( match ) {
1400                         *matchp = match;
1401                         return LDAP_SUCCESS;
1402                 }
1403
1404         } else if ( !approx && valueUID.bv_len ) {
1405                 match = -1;
1406                 *matchp = match;
1407                 return LDAP_SUCCESS;
1408
1409         } else if ( !approx && assertedUID.bv_len ) {
1410                 match = 1;
1411                 *matchp = match;
1412                 return LDAP_SUCCESS;
1413         }
1414
1415         return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1416 }
1417
1418 static int 
1419 uniqueMemberIndexer(
1420         slap_mask_t use,
1421         slap_mask_t flags,
1422         Syntax *syntax,
1423         MatchingRule *mr,
1424         struct berval *prefix,
1425         BerVarray values,
1426         BerVarray *keysp,
1427         void *ctx )
1428 {
1429         BerVarray dnvalues;
1430         int rc;
1431         int i;
1432         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1433                 /* just count them */                 
1434         }
1435         assert( i > 0 );
1436
1437         dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1438
1439         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1440                 struct berval assertedDN = values[i];
1441                 struct berval assertedUID = BER_BVNULL;
1442
1443                 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1444                         assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1445                         if ( !BER_BVISNULL( &assertedUID ) ) {
1446                                 assertedUID.bv_val++;
1447                                 assertedUID.bv_len = assertedDN.bv_len
1448                                         - ( assertedUID.bv_val - assertedDN.bv_val );
1449         
1450                                 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1451                                         assertedDN.bv_len -= assertedUID.bv_len + 1;
1452
1453                                 } else {
1454                                         BER_BVZERO( &assertedUID );
1455                                 }
1456                         }
1457                 }
1458
1459                 dnvalues[i] = assertedDN;
1460         }
1461         BER_BVZERO( &dnvalues[i] );
1462
1463         rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1464                 dnvalues, keysp, ctx );
1465
1466         slap_sl_free( dnvalues, ctx );
1467         return rc;
1468 }
1469
1470 static int 
1471 uniqueMemberFilter(
1472         slap_mask_t use,
1473         slap_mask_t flags,
1474         Syntax *syntax,
1475         MatchingRule *mr,
1476         struct berval *prefix,
1477         void * assertedValue,
1478         BerVarray *keysp,
1479         void *ctx )
1480 {
1481         struct berval *asserted = (struct berval *) assertedValue;
1482         struct berval assertedDN = *asserted;
1483         struct berval assertedUID = BER_BVNULL;
1484
1485         if ( !BER_BVISEMPTY( asserted ) ) {
1486                 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1487                 if ( !BER_BVISNULL( &assertedUID ) ) {
1488                         assertedUID.bv_val++;
1489                         assertedUID.bv_len = assertedDN.bv_len
1490                                 - ( assertedUID.bv_val - assertedDN.bv_val );
1491
1492                         if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1493                                 assertedDN.bv_len -= assertedUID.bv_len + 1;
1494
1495                         } else {
1496                                 BER_BVZERO( &assertedUID );
1497                         }
1498                 }
1499         }
1500
1501         return octetStringFilter( use, flags, syntax, mr, prefix,
1502                 &assertedDN, keysp, ctx );
1503 }
1504
1505
1506 /*
1507  * Handling boolean syntax and matching is quite rigid.
1508  * A more flexible approach would be to allow a variety
1509  * of strings to be normalized and prettied into TRUE
1510  * and FALSE.
1511  */
1512 static int
1513 booleanValidate(
1514         Syntax *syntax,
1515         struct berval *in )
1516 {
1517         /* very unforgiving validation, requires no normalization
1518          * before simplistic matching
1519          */
1520
1521         if( in->bv_len == 4 ) {
1522                 if( bvmatch( in, &slap_true_bv ) ) {
1523                         return LDAP_SUCCESS;
1524                 }
1525         } else if( in->bv_len == 5 ) {
1526                 if( bvmatch( in, &slap_false_bv ) ) {
1527                         return LDAP_SUCCESS;
1528                 }
1529         }
1530
1531         return LDAP_INVALID_SYNTAX;
1532 }
1533
1534 static int
1535 booleanMatch(
1536         int *matchp,
1537         slap_mask_t flags,
1538         Syntax *syntax,
1539         MatchingRule *mr,
1540         struct berval *value,
1541         void *assertedValue )
1542 {
1543         /* simplistic matching allowed by rigid validation */
1544         struct berval *asserted = (struct berval *) assertedValue;
1545         *matchp = value->bv_len != asserted->bv_len;
1546         return LDAP_SUCCESS;
1547 }
1548
1549 /*-------------------------------------------------------------------
1550 LDAP/X.500 string syntax / matching rules have a few oddities.  This
1551 comment attempts to detail how slapd(8) treats them.
1552
1553 Summary:
1554   StringSyntax          X.500   LDAP    Matching/Comments
1555   DirectoryString       CHOICE  UTF8    i/e + ignore insignificant spaces
1556   PrintableString       subset  subset  i/e + ignore insignificant spaces
1557   PrintableString       subset  subset  i/e + ignore insignificant spaces
1558   NumericString         subset  subset  ignore all spaces
1559   IA5String                     ASCII   ASCII   i/e + ignore insignificant spaces
1560   TeletexString         T.61    T.61    i/e + ignore insignificant spaces
1561
1562   TelephoneNumber       subset  subset  i + ignore all spaces and "-"
1563
1564   See RFC 4518 for details.
1565
1566
1567 Directory String -
1568   In X.500(93), a directory string can be either a PrintableString,
1569   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1570   In later versions, more CHOICEs were added.  In all cases the string
1571   must be non-empty.
1572
1573   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1574   A directory string cannot be zero length.
1575
1576   For matching, there are both case ignore and exact rules.  Both
1577   also require that "insignificant" spaces be ignored.
1578         spaces before the first non-space are ignored;
1579         spaces after the last non-space are ignored;
1580         spaces after a space are ignored.
1581   Note: by these rules (and as clarified in X.520), a string of only
1582   spaces is to be treated as if held one space, not empty (which
1583   would be a syntax error).
1584
1585 NumericString
1586   In ASN.1, numeric string is just a string of digits and spaces
1587   and could be empty.  However, in X.500, all attribute values of
1588   numeric string carry a non-empty constraint.  For example:
1589
1590         internationalISDNNumber ATTRIBUTE ::= {
1591                 WITH SYNTAX InternationalISDNNumber
1592                 EQUALITY MATCHING RULE numericStringMatch
1593                 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1594                 ID id-at-internationalISDNNumber }
1595         InternationalISDNNumber ::=
1596             NumericString (SIZE(1..ub-international-isdn-number))
1597
1598   Unforunately, some assertion values are don't carry the same
1599   constraint (but its unclear how such an assertion could ever
1600   be true). In LDAP, there is one syntax (numericString) not two
1601   (numericString with constraint, numericString without constraint).
1602   This should be treated as numericString with non-empty constraint.
1603   Note that while someone may have no ISDN number, there are no ISDN
1604   numbers which are zero length.
1605
1606   In matching, spaces are ignored.
1607
1608 PrintableString
1609   In ASN.1, Printable string is just a string of printable characters
1610   and can be empty.  In X.500, semantics much like NumericString (see
1611   serialNumber for a like example) excepting uses insignificant space
1612   handling instead of ignore all spaces.  They must be non-empty.
1613
1614 IA5String
1615   Basically same as PrintableString.  There are no examples in X.500,
1616   but same logic applies.  Empty strings are allowed.
1617
1618 -------------------------------------------------------------------*/
1619
1620 static int
1621 UTF8StringValidate(
1622         Syntax *syntax,
1623         struct berval *in )
1624 {
1625         ber_len_t count;
1626         int len;
1627         unsigned char *u = (unsigned char *)in->bv_val;
1628
1629         if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1630                 /* directory strings cannot be empty */
1631                 return LDAP_INVALID_SYNTAX;
1632         }
1633
1634         for( count = in->bv_len; count > 0; count -= len, u += len ) {
1635                 /* get the length indicated by the first byte */
1636                 len = LDAP_UTF8_CHARLEN2( u, len );
1637
1638                 /* very basic checks */
1639                 switch( len ) {
1640                         case 6:
1641                                 if( (u[5] & 0xC0) != 0x80 ) {
1642                                         return LDAP_INVALID_SYNTAX;
1643                                 }
1644                         case 5:
1645                                 if( (u[4] & 0xC0) != 0x80 ) {
1646                                         return LDAP_INVALID_SYNTAX;
1647                                 }
1648                         case 4:
1649                                 if( (u[3] & 0xC0) != 0x80 ) {
1650                                         return LDAP_INVALID_SYNTAX;
1651                                 }
1652                         case 3:
1653                                 if( (u[2] & 0xC0 )!= 0x80 ) {
1654                                         return LDAP_INVALID_SYNTAX;
1655                                 }
1656                         case 2:
1657                                 if( (u[1] & 0xC0) != 0x80 ) {
1658                                         return LDAP_INVALID_SYNTAX;
1659                                 }
1660                         case 1:
1661                                 /* CHARLEN already validated it */
1662                                 break;
1663                         default:
1664                                 return LDAP_INVALID_SYNTAX;
1665                 }
1666
1667                 /* make sure len corresponds with the offset
1668                         to the next character */
1669                 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1670         }
1671
1672         if( count != 0 ) {
1673                 return LDAP_INVALID_SYNTAX;
1674         }
1675
1676         return LDAP_SUCCESS;
1677 }
1678
1679 static int
1680 UTF8StringNormalize(
1681         slap_mask_t use,
1682         Syntax *syntax,
1683         MatchingRule *mr,
1684         struct berval *val,
1685         struct berval *normalized,
1686         void *ctx )
1687 {
1688         struct berval tmp, nvalue;
1689         int flags, wasspace;
1690         ber_len_t i;
1691
1692         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
1693
1694         if( BER_BVISNULL( val ) ) {
1695                 /* assume we're dealing with a syntax (e.g., UTF8String)
1696                  * which allows empty strings
1697                  */
1698                 BER_BVZERO( normalized );
1699                 return LDAP_SUCCESS;
1700         }
1701
1702         flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1703                 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1704         flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1705                 ? LDAP_UTF8_APPROX : 0;
1706
1707         val = UTF8bvnormalize( val, &tmp, flags, ctx );
1708         if( val == NULL ) {
1709                 return LDAP_OTHER;
1710         }
1711         
1712         /* collapse spaces (in place) */
1713         nvalue.bv_len = 0;
1714         nvalue.bv_val = tmp.bv_val;
1715
1716         /* trim leading spaces? */
1717         wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1718                 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1719
1720         for( i = 0; i < tmp.bv_len; i++) {
1721                 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1722                         if( wasspace++ == 0 ) {
1723                                 /* trim repeated spaces */
1724                                 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1725                         }
1726                 } else {
1727                         wasspace = 0;
1728                         nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1729                 }
1730         }
1731
1732         if( !BER_BVISEMPTY( &nvalue ) ) {
1733                 /* trim trailing space? */
1734                 if( wasspace && (
1735                         (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1736                         ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1737                 {
1738                         --nvalue.bv_len;
1739                 }
1740                 nvalue.bv_val[nvalue.bv_len] = '\0';
1741
1742         } else {
1743                 /* string of all spaces is treated as one space */
1744                 nvalue.bv_val[0] = ' ';
1745                 nvalue.bv_val[1] = '\0';
1746                 nvalue.bv_len = 1;
1747         }
1748
1749         *normalized = nvalue;
1750         return LDAP_SUCCESS;
1751 }
1752
1753 static int
1754 directoryStringSubstringsMatch(
1755         int *matchp,
1756         slap_mask_t flags,
1757         Syntax *syntax,
1758         MatchingRule *mr,
1759         struct berval *value,
1760         void *assertedValue )
1761 {
1762         int match = 0;
1763         SubstringsAssertion *sub = assertedValue;
1764         struct berval left = *value;
1765         ber_len_t i;
1766         int priorspace=0;
1767
1768         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1769                 if ( sub->sa_initial.bv_len > left.bv_len ) {
1770                         /* not enough left */
1771                         match = 1;
1772                         goto done;
1773                 }
1774
1775                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1776                         sub->sa_initial.bv_len );
1777
1778                 if ( match != 0 ) {
1779                         goto done;
1780                 }
1781
1782                 left.bv_val += sub->sa_initial.bv_len;
1783                 left.bv_len -= sub->sa_initial.bv_len;
1784
1785                 priorspace = ASCII_SPACE(
1786                         sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1787         }
1788
1789         if ( sub->sa_any ) {
1790                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1791                         ber_len_t idx;
1792                         char *p;
1793
1794                         if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] ) 
1795                                 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1796                         { 
1797                                 /* allow next space to match */
1798                                 left.bv_val--;
1799                                 left.bv_len++;
1800                         }
1801                         priorspace=0;
1802
1803 retry:
1804                         if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1805                                 continue;
1806                         }
1807
1808                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1809                                 /* not enough left */
1810                                 match = 1;
1811                                 goto done;
1812                         }
1813
1814                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1815
1816                         if( p == NULL ) {
1817                                 match = 1;
1818                                 goto done;
1819                         }
1820
1821                         idx = p - left.bv_val;
1822
1823                         if ( idx >= left.bv_len ) {
1824                                 /* this shouldn't happen */
1825                                 return LDAP_OTHER;
1826                         }
1827
1828                         left.bv_val = p;
1829                         left.bv_len -= idx;
1830
1831                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1832                                 /* not enough left */
1833                                 match = 1;
1834                                 goto done;
1835                         }
1836
1837                         match = memcmp( left.bv_val,
1838                                 sub->sa_any[i].bv_val,
1839                                 sub->sa_any[i].bv_len );
1840
1841                         if ( match != 0 ) {
1842                                 left.bv_val++;
1843                                 left.bv_len--;
1844                                 goto retry;
1845                         }
1846
1847                         left.bv_val += sub->sa_any[i].bv_len;
1848                         left.bv_len -= sub->sa_any[i].bv_len;
1849
1850                         priorspace = ASCII_SPACE(
1851                                 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1852                 }
1853         }
1854
1855         if ( !BER_BVISNULL( &sub->sa_final ) ) {
1856                 if( priorspace && !BER_BVISEMPTY( &sub->sa_final ) 
1857                         && ASCII_SPACE( sub->sa_final.bv_val[0] ))
1858                 { 
1859                         /* allow next space to match */
1860                         left.bv_val--;
1861                         left.bv_len++;
1862                 }
1863
1864                 if ( sub->sa_final.bv_len > left.bv_len ) {
1865                         /* not enough left */
1866                         match = 1;
1867                         goto done;
1868                 }
1869
1870                 match = memcmp( sub->sa_final.bv_val,
1871                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1872                         sub->sa_final.bv_len );
1873
1874                 if ( match != 0 ) {
1875                         goto done;
1876                 }
1877         }
1878
1879 done:
1880         *matchp = match;
1881         return LDAP_SUCCESS;
1882 }
1883
1884 #if defined(SLAPD_APPROX_INITIALS)
1885 #       define SLAPD_APPROX_DELIMITER "._ "
1886 #       define SLAPD_APPROX_WORDLEN 2
1887 #else
1888 #       define SLAPD_APPROX_DELIMITER " "
1889 #       define SLAPD_APPROX_WORDLEN 1
1890 #endif
1891
1892 static int
1893 approxMatch(
1894         int *matchp,
1895         slap_mask_t flags,
1896         Syntax *syntax,
1897         MatchingRule *mr,
1898         struct berval *value,
1899         void *assertedValue )
1900 {
1901         struct berval *nval, *assertv;
1902         char *val, **values, **words, *c;
1903         int i, count, len, nextchunk=0, nextavail=0;
1904
1905         /* Yes, this is necessary */
1906         nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
1907         if( nval == NULL ) {
1908                 *matchp = 1;
1909                 return LDAP_SUCCESS;
1910         }
1911
1912         /* Yes, this is necessary */
1913         assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1914                 NULL, LDAP_UTF8_APPROX, NULL );
1915         if( assertv == NULL ) {
1916                 ber_bvfree( nval );
1917                 *matchp = 1;
1918                 return LDAP_SUCCESS;
1919         }
1920
1921         /* Isolate how many words there are */
1922         for ( c = nval->bv_val, count = 1; *c; c++ ) {
1923                 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1924                 if ( c == NULL ) break;
1925                 *c = '\0';
1926                 count++;
1927         }
1928
1929         /* Get a phonetic copy of each word */
1930         words = (char **)ch_malloc( count * sizeof(char *) );
1931         values = (char **)ch_malloc( count * sizeof(char *) );
1932         for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
1933                 words[i] = c;
1934                 values[i] = phonetic(c);
1935         }
1936
1937         /* Work through the asserted value's words, to see if at least some
1938          * of the words are there, in the same order. */
1939         len = 0;
1940         while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1941                 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1942                 if( len == 0 ) {
1943                         nextchunk++;
1944                         continue;
1945                 }
1946 #if defined(SLAPD_APPROX_INITIALS)
1947                 else if( len == 1 ) {
1948                         /* Single letter words need to at least match one word's initial */
1949                         for( i=nextavail; i<count; i++ )
1950                                 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1951                                         nextavail=i+1;
1952                                         break;
1953                                 }
1954                 }
1955 #endif
1956                 else {
1957                         /* Isolate the next word in the asserted value and phonetic it */
1958                         assertv->bv_val[nextchunk+len] = '\0';
1959                         val = phonetic( assertv->bv_val + nextchunk );
1960
1961                         /* See if this phonetic chunk is in the remaining words of *value */
1962                         for( i=nextavail; i<count; i++ ){
1963                                 if( !strcmp( val, values[i] ) ){
1964                                         nextavail = i+1;
1965                                         break;
1966                                 }
1967                         }
1968                         ch_free( val );
1969                 }
1970
1971                 /* This chunk in the asserted value was NOT within the *value. */
1972                 if( i >= count ) {
1973                         nextavail=-1;
1974                         break;
1975                 }
1976
1977                 /* Go on to the next word in the asserted value */
1978                 nextchunk += len+1;
1979         }
1980
1981         /* If some of the words were seen, call it a match */
1982         if( nextavail > 0 ) {
1983                 *matchp = 0;
1984         }
1985         else {
1986                 *matchp = 1;
1987         }
1988
1989         /* Cleanup allocs */
1990         ber_bvfree( assertv );
1991         for( i=0; i<count; i++ ) {
1992                 ch_free( values[i] );
1993         }
1994         ch_free( values );
1995         ch_free( words );
1996         ber_bvfree( nval );
1997
1998         return LDAP_SUCCESS;
1999 }
2000
2001 static int 
2002 approxIndexer(
2003         slap_mask_t use,
2004         slap_mask_t flags,
2005         Syntax *syntax,
2006         MatchingRule *mr,
2007         struct berval *prefix,
2008         BerVarray values,
2009         BerVarray *keysp,
2010         void *ctx )
2011 {
2012         char *c;
2013         int i,j, len, wordcount, keycount=0;
2014         struct berval *newkeys;
2015         BerVarray keys=NULL;
2016
2017         for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
2018                 struct berval val = BER_BVNULL;
2019                 /* Yes, this is necessary */
2020                 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
2021                 assert( !BER_BVISNULL( &val ) );
2022
2023                 /* Isolate how many words there are. There will be a key for each */
2024                 for( wordcount = 0, c = val.bv_val; *c; c++) {
2025                         len = strcspn(c, SLAPD_APPROX_DELIMITER);
2026                         if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
2027                         c+= len;
2028                         if (*c == '\0') break;
2029                         *c = '\0';
2030                 }
2031
2032                 /* Allocate/increase storage to account for new keys */
2033                 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
2034                         * sizeof(struct berval) );
2035                 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
2036                 if( keys ) ch_free( keys );
2037                 keys = newkeys;
2038
2039                 /* Get a phonetic copy of each word */
2040                 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
2041                         len = strlen( c );
2042                         if( len < SLAPD_APPROX_WORDLEN ) continue;
2043                         ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
2044                         keycount++;
2045                         i++;
2046                 }
2047
2048                 ber_memfree( val.bv_val );
2049         }
2050         BER_BVZERO( &keys[keycount] );
2051         *keysp = keys;
2052
2053         return LDAP_SUCCESS;
2054 }
2055
2056 static int 
2057 approxFilter(
2058         slap_mask_t use,
2059         slap_mask_t flags,
2060         Syntax *syntax,
2061         MatchingRule *mr,
2062         struct berval *prefix,
2063         void * assertedValue,
2064         BerVarray *keysp,
2065         void *ctx )
2066 {
2067         char *c;
2068         int i, count, len;
2069         struct berval *val;
2070         BerVarray keys;
2071
2072         /* Yes, this is necessary */
2073         val = UTF8bvnormalize( ((struct berval *)assertedValue),
2074                 NULL, LDAP_UTF8_APPROX, NULL );
2075         if( val == NULL || BER_BVISNULL( val ) ) {
2076                 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
2077                 BER_BVZERO( &keys[0] );
2078                 *keysp = keys;
2079                 ber_bvfree( val );
2080                 return LDAP_SUCCESS;
2081         }
2082
2083         /* Isolate how many words there are. There will be a key for each */
2084         for( count = 0,c = val->bv_val; *c; c++) {
2085                 len = strcspn(c, SLAPD_APPROX_DELIMITER);
2086                 if( len >= SLAPD_APPROX_WORDLEN ) count++;
2087                 c+= len;
2088                 if (*c == '\0') break;
2089                 *c = '\0';
2090         }
2091
2092         /* Allocate storage for new keys */
2093         keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
2094
2095         /* Get a phonetic copy of each word */
2096         for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
2097                 len = strlen(c);
2098                 if( len < SLAPD_APPROX_WORDLEN ) continue;
2099                 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
2100                 i++;
2101         }
2102
2103         ber_bvfree( val );
2104
2105         BER_BVZERO( &keys[count] );
2106         *keysp = keys;
2107
2108         return LDAP_SUCCESS;
2109 }
2110
2111 /* Remove all spaces and '-' characters */
2112 static int
2113 telephoneNumberNormalize(
2114         slap_mask_t usage,
2115         Syntax *syntax,
2116         MatchingRule *mr,
2117         struct berval *val,
2118         struct berval *normalized,
2119         void *ctx )
2120 {
2121         char *p, *q;
2122
2123         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
2124
2125         /* validator should have refused an empty string */
2126         assert( !BER_BVISEMPTY( val ) );
2127
2128         q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2129
2130         for( p = val->bv_val; *p; p++ ) {
2131                 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
2132                         *q++ = *p;
2133                 }
2134         }
2135         *q = '\0';
2136
2137         normalized->bv_len = q - normalized->bv_val;
2138
2139         if( BER_BVISEMPTY( normalized ) ) {
2140                 slap_sl_free( normalized->bv_val, ctx );
2141                 BER_BVZERO( normalized );
2142                 return LDAP_INVALID_SYNTAX;
2143         }
2144
2145         return LDAP_SUCCESS;
2146 }
2147
2148 static int
2149 postalAddressValidate(
2150         Syntax *syntax,
2151         struct berval *in )
2152 {
2153         struct berval bv = *in;
2154         ber_len_t c;
2155
2156         for ( c = 0; c < in->bv_len; c++ ) {
2157                 if ( in->bv_val[c] == '\\' ) {
2158                         c++;
2159                         if ( strncasecmp( &in->bv_val[c], "24", STRLENOF( "24" ) ) != 0
2160                                 && strncasecmp( &in->bv_val[c], "5C", STRLENOF( "5C" ) ) != 0 )
2161                         {
2162                                 return LDAP_INVALID_SYNTAX;
2163                         }
2164                         continue;
2165                 }
2166
2167                 if ( in->bv_val[c] == '$' ) {
2168                         bv.bv_len = &in->bv_val[c] - bv.bv_val;
2169                         if ( UTF8StringValidate( NULL, &bv ) != LDAP_SUCCESS ) {
2170                                 return LDAP_INVALID_SYNTAX;
2171                         }
2172                         bv.bv_val = &in->bv_val[c] + 1;
2173                 }
2174         }
2175
2176         bv.bv_len = &in->bv_val[c] - bv.bv_val;
2177         return UTF8StringValidate( NULL, &bv );
2178 }
2179
2180 static int
2181 postalAddressNormalize(
2182         slap_mask_t usage,
2183         Syntax *syntax,
2184         MatchingRule *mr,
2185         struct berval *val,
2186         struct berval *normalized,
2187         void *ctx )
2188 {
2189         BerVarray lines = NULL, nlines = NULL;
2190         ber_len_t l, c;
2191         int rc = LDAP_SUCCESS;
2192         MatchingRule *xmr = NULL;
2193         char *p;
2194
2195         if ( SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseIgnoreListMatch ) ) {
2196                 xmr = slap_schema.si_mr_caseIgnoreMatch;
2197
2198         } else {
2199                 xmr = slap_schema.si_mr_caseExactMatch;
2200         }
2201
2202         for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2203                 if ( val->bv_val[c] == '$' ) {
2204                         l++;
2205                 }
2206         }
2207
2208         lines = slap_sl_calloc( sizeof( struct berval ), 2 * ( l + 2 ), ctx );
2209         nlines = &lines[l + 2];
2210
2211         lines[0].bv_val = val->bv_val;
2212         for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2213                 if ( val->bv_val[c] == '$' ) {
2214                         lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2215                         l++;
2216                         lines[l].bv_val = &val->bv_val[c + 1];
2217                 }
2218         }
2219         lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2220
2221         normalized->bv_len = l;
2222
2223         for ( l = 0; !BER_BVISNULL( &lines[l] ); l++ ) {
2224                 /* NOTE: we directly normalize each line,
2225                  * without unescaping the values, since the special
2226                  * values '\24' ('$') and '\5C' ('\') are not affected
2227                  * by normalization */
2228                 rc = UTF8StringNormalize( usage, NULL, xmr, &lines[l], &nlines[l], ctx );
2229                 if ( rc != LDAP_SUCCESS ) {
2230                         rc = LDAP_INVALID_SYNTAX;
2231                         goto done;
2232                 }
2233
2234                 normalized->bv_len += nlines[l].bv_len;
2235         }
2236
2237         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2238
2239         p = normalized->bv_val;
2240         for ( l = 0; !BER_BVISNULL( &nlines[l] ); l++ ) {
2241                 p = lutil_strncopy( p, nlines[l].bv_val, nlines[l].bv_len );
2242
2243                 *p++ = '$';
2244         }
2245         *--p = '\0';
2246
2247         assert( p == &normalized->bv_val[normalized->bv_len] );
2248
2249 done:;
2250         if ( nlines != NULL ) {
2251                 for ( l = 0; !BER_BVISNULL( &nlines[ l ] ); l++ ) {
2252                         slap_sl_free( nlines[l].bv_val, ctx );
2253                 }
2254
2255                 slap_sl_free( lines, ctx );
2256         }
2257
2258         return rc;
2259 }
2260
2261 int
2262 numericoidValidate(
2263         Syntax *syntax,
2264         struct berval *in )
2265 {
2266         struct berval val = *in;
2267
2268         if( BER_BVISEMPTY( &val ) ) {
2269                 /* disallow empty strings */
2270                 return LDAP_INVALID_SYNTAX;
2271         }
2272
2273         while( OID_LEADCHAR( val.bv_val[0] ) ) {
2274                 if ( val.bv_len == 1 ) {
2275                         return LDAP_SUCCESS;
2276                 }
2277
2278                 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2279                         break;
2280                 }
2281
2282                 val.bv_val++;
2283                 val.bv_len--;
2284
2285                 while ( OID_LEADCHAR( val.bv_val[0] )) {
2286                         val.bv_val++;
2287                         val.bv_len--;
2288
2289                         if ( val.bv_len == 0 ) {
2290                                 return LDAP_SUCCESS;
2291                         }
2292                 }
2293
2294                 if( !OID_SEPARATOR( val.bv_val[0] )) {
2295                         break;
2296                 }
2297
2298                 val.bv_val++;
2299                 val.bv_len--;
2300         }
2301
2302         return LDAP_INVALID_SYNTAX;
2303 }
2304
2305 static int
2306 integerValidate(
2307         Syntax *syntax,
2308         struct berval *in )
2309 {
2310         ber_len_t i;
2311         struct berval val = *in;
2312
2313         if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2314
2315         if ( val.bv_val[0] == '-' ) {
2316                 val.bv_len--;
2317                 val.bv_val++;
2318
2319                 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2320                         return LDAP_INVALID_SYNTAX;
2321                 }
2322
2323                 if( val.bv_val[0] == '0' ) { /* "-0" */
2324                         return LDAP_INVALID_SYNTAX;
2325                 }
2326
2327         } else if ( val.bv_val[0] == '0' ) {
2328                 if( val.bv_len > 1 ) { /* "0<more>" */
2329                         return LDAP_INVALID_SYNTAX;
2330                 }
2331
2332                 return LDAP_SUCCESS;
2333         }
2334
2335         for( i=0; i < val.bv_len; i++ ) {
2336                 if( !ASCII_DIGIT(val.bv_val[i]) ) {
2337                         return LDAP_INVALID_SYNTAX;
2338                 }
2339         }
2340
2341         return LDAP_SUCCESS;
2342 }
2343
2344 static int
2345 integerMatch(
2346         int *matchp,
2347         slap_mask_t flags,
2348         Syntax *syntax,
2349         MatchingRule *mr,
2350         struct berval *value,
2351         void *assertedValue )
2352 {
2353         struct berval *asserted = (struct berval *) assertedValue;
2354         int vsign = 1, asign = 1;       /* default sign = '+' */
2355         struct berval v, a;
2356         int match;
2357
2358         v = *value;
2359         if( v.bv_val[0] == '-' ) {
2360                 vsign = -1;
2361                 v.bv_val++;
2362                 v.bv_len--;
2363         }
2364
2365         if( BER_BVISEMPTY( &v ) ) vsign = 0;
2366
2367         a = *asserted;
2368         if( a.bv_val[0] == '-' ) {
2369                 asign = -1;
2370                 a.bv_val++;
2371                 a.bv_len--;
2372         }
2373
2374         if( BER_BVISEMPTY( &a ) ) vsign = 0;
2375
2376         match = vsign - asign;
2377         if( match == 0 ) {
2378                 match = ( v.bv_len != a.bv_len
2379                         ? ( v.bv_len < a.bv_len ? -1 : 1 )
2380                         : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2381                 if( vsign < 0 ) match = -match;
2382         }
2383
2384         *matchp = match;
2385         return LDAP_SUCCESS;
2386 }
2387
2388 /* 10**Chop < 256**Chopbytes and Chop > Chopbytes<<1 (for sign bit and itmp) */
2389 #define INDEX_INTLEN_CHOP 7
2390 #define INDEX_INTLEN_CHOPBYTES 3
2391
2392 static int
2393 integerVal2Key(
2394         struct berval *in,
2395         struct berval *key,
2396         struct berval *tmp,
2397         void *ctx )
2398 {
2399         /* index format:
2400          * only if too large: one's complement <sign*exponent (chopped bytes)>,
2401          * two's complement value (sign-extended or chopped as needed),
2402          * however the top <number of exponent-bytes + 1> bits of first byte
2403          * above is the inverse sign.   The next bit is the sign as delimiter.
2404          */
2405         ber_slen_t k = index_intlen_strlen;
2406         ber_len_t chop = 0;
2407         unsigned signmask = ~0x7fU;
2408         unsigned char lenbuf[sizeof(k) + 2], *lenp, neg = 0xff;
2409         struct berval val = *in, itmp = *tmp;
2410
2411         if ( val.bv_val[0] != '-' ) {
2412                 neg = 0;
2413                 --k;
2414         }
2415
2416         /* Chop least significant digits, increase length instead */
2417         if ( val.bv_len > (ber_len_t) k ) {
2418                 chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
2419                 val.bv_len -= chop * INDEX_INTLEN_CHOP; /* #digits chopped */
2420                 chop *= INDEX_INTLEN_CHOPBYTES;         /* #bytes added */
2421         }
2422
2423         if ( lutil_str2bin( &val, &itmp, ctx )) {
2424                 return LDAP_INVALID_SYNTAX;
2425         }
2426
2427         /* Omit leading sign byte */
2428         if ( itmp.bv_val[0] == neg ) {
2429                 itmp.bv_val++;
2430                 itmp.bv_len--;
2431         }
2432
2433         k = (ber_slen_t) index_intlen - (ber_slen_t) (itmp.bv_len + chop);
2434         if ( k > 0 ) {
2435                 assert( chop == 0 );
2436                 memset( key->bv_val, neg, k );  /* sign-extend */
2437         } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
2438                 lenp = lenbuf + sizeof(lenbuf);
2439                 chop = - (ber_len_t) k;
2440                 do {
2441                         *--lenp = ((unsigned char) chop & 0xff) ^ neg;
2442                         signmask >>= 1;
2443                 } while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) );
2444                 /* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff)
2445                  * are 1, and the top n+2 bits of lenp[] are the sign bit. */
2446                 k = (lenbuf + sizeof(lenbuf)) - lenp;
2447                 if ( k > (ber_slen_t) index_intlen )
2448                         k = index_intlen;
2449                 memcpy( key->bv_val, lenp, k );
2450                 itmp.bv_len = index_intlen - k;
2451         }
2452         memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
2453         key->bv_val[0] ^= (unsigned char) signmask & 0xff; /* invert sign */
2454         return 0;
2455 }
2456
2457 /* Index generation function */
2458 static int
2459 integerIndexer(
2460         slap_mask_t use,
2461         slap_mask_t flags,
2462         Syntax *syntax,
2463         MatchingRule *mr,
2464         struct berval *prefix,
2465         BerVarray values,
2466         BerVarray *keysp,
2467         void *ctx )
2468 {
2469         char ibuf[64];
2470         struct berval itmp;
2471         BerVarray keys;
2472         ber_len_t vlen;
2473         int i, rc;
2474         unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2475
2476         /* count the values and find max needed length */
2477         vlen = 0;
2478         for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2479                 if ( vlen < values[i].bv_len )
2480                         vlen = values[i].bv_len;
2481         }
2482         if ( vlen > maxstrlen )
2483                 vlen = maxstrlen;
2484
2485         /* we should have at least one value at this point */
2486         assert( i > 0 );
2487
2488         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2489         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2490                 keys[i].bv_len = index_intlen;
2491                 keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
2492         }
2493         keys[i].bv_len = 0;
2494         keys[i].bv_val = NULL;
2495
2496         if ( vlen > sizeof(ibuf) ) {
2497                 itmp.bv_val = slap_sl_malloc( vlen, ctx );
2498         } else {
2499                 itmp.bv_val = ibuf;
2500         }
2501         itmp.bv_len = sizeof(ibuf);
2502
2503         for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2504                 if ( itmp.bv_val != ibuf ) {
2505                         itmp.bv_len = values[i].bv_len;
2506                         if ( itmp.bv_len <= sizeof(ibuf) )
2507                                 itmp.bv_len = sizeof(ibuf);
2508                         else if ( itmp.bv_len > maxstrlen )
2509                                 itmp.bv_len = maxstrlen;
2510                 }
2511                 rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
2512                 if ( rc )
2513                         goto func_leave;
2514         }
2515         *keysp = keys;
2516 func_leave:
2517         if ( itmp.bv_val != ibuf ) {
2518                 slap_sl_free( itmp.bv_val, ctx );
2519         }
2520         return rc;
2521 }
2522
2523 /* Index generation function */
2524 static int
2525 integerFilter(
2526         slap_mask_t use,
2527         slap_mask_t flags,
2528         Syntax *syntax,
2529         MatchingRule *mr,
2530         struct berval *prefix,
2531         void * assertedValue,
2532         BerVarray *keysp,
2533         void *ctx )
2534 {
2535         char ibuf[64];
2536         struct berval iv;
2537         BerVarray keys;
2538         struct berval *value;
2539         int rc;
2540
2541         value = (struct berval *) assertedValue;
2542
2543         keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2544
2545         keys[0].bv_len = index_intlen;
2546         keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
2547         keys[1].bv_len = 0;
2548         keys[1].bv_val = NULL;
2549
2550         iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
2551                 ? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2552         if ( iv.bv_len > (int) sizeof(ibuf) ) {
2553                 iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
2554         } else {
2555                 iv.bv_val = ibuf;
2556                 iv.bv_len = sizeof(ibuf);
2557         }
2558
2559         rc = integerVal2Key( value, keys, &iv, ctx );
2560         if ( rc == 0 )
2561                 *keysp = keys;
2562
2563         if ( iv.bv_val != ibuf ) {
2564                 slap_sl_free( iv.bv_val, ctx );
2565         }
2566         return rc;
2567 }
2568
2569 static int
2570 countryStringValidate(
2571         Syntax *syntax,
2572         struct berval *val )
2573 {
2574         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2575
2576         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2577                 return LDAP_INVALID_SYNTAX;
2578         }
2579         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2580                 return LDAP_INVALID_SYNTAX;
2581         }
2582
2583         return LDAP_SUCCESS;
2584 }
2585
2586 static int
2587 printableStringValidate(
2588         Syntax *syntax,
2589         struct berval *val )
2590 {
2591         ber_len_t i;
2592
2593         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2594
2595         for(i=0; i < val->bv_len; i++) {
2596                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2597                         return LDAP_INVALID_SYNTAX;
2598                 }
2599         }
2600
2601         return LDAP_SUCCESS;
2602 }
2603
2604 static int
2605 printablesStringValidate(
2606         Syntax *syntax,
2607         struct berval *val )
2608 {
2609         ber_len_t i, len;
2610
2611         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2612
2613         for(i=0,len=0; i < val->bv_len; i++) {
2614                 int c = val->bv_val[i];
2615
2616                 if( c == '$' ) {
2617                         if( len == 0 ) {
2618                                 return LDAP_INVALID_SYNTAX;
2619                         }
2620                         len = 0;
2621
2622                 } else if ( SLAP_PRINTABLE(c) ) {
2623                         len++;
2624                 } else {
2625                         return LDAP_INVALID_SYNTAX;
2626                 }
2627         }
2628
2629         if( len == 0 ) {
2630                 return LDAP_INVALID_SYNTAX;
2631         }
2632
2633         return LDAP_SUCCESS;
2634 }
2635
2636 static int
2637 IA5StringValidate(
2638         Syntax *syntax,
2639         struct berval *val )
2640 {
2641         ber_len_t i;
2642
2643         for(i=0; i < val->bv_len; i++) {
2644                 if( !LDAP_ASCII(val->bv_val[i]) ) {
2645                         return LDAP_INVALID_SYNTAX;
2646                 }
2647         }
2648
2649         return LDAP_SUCCESS;
2650 }
2651
2652 static int
2653 IA5StringNormalize(
2654         slap_mask_t use,
2655         Syntax *syntax,
2656         MatchingRule *mr,
2657         struct berval *val,
2658         struct berval *normalized,
2659         void *ctx )
2660 {
2661         char *p, *q;
2662         int casefold = !SLAP_MR_ASSOCIATED( mr,
2663                 slap_schema.si_mr_caseExactIA5Match );
2664
2665         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2666
2667         p = val->bv_val;
2668
2669         /* Ignore initial whitespace */
2670         while ( ASCII_SPACE( *p ) ) p++;
2671
2672         normalized->bv_len = val->bv_len - ( p - val->bv_val );
2673         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2674         AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2675         normalized->bv_val[normalized->bv_len] = '\0';
2676
2677         p = q = normalized->bv_val;
2678
2679         while ( *p ) {
2680                 if ( ASCII_SPACE( *p ) ) {
2681                         *q++ = *p++;
2682
2683                         /* Ignore the extra whitespace */
2684                         while ( ASCII_SPACE( *p ) ) {
2685                                 p++;
2686                         }
2687
2688                 } else if ( casefold ) {
2689                         /* Most IA5 rules require casefolding */
2690                         *q++ = TOLOWER(*p); p++;
2691
2692                 } else {
2693                         *q++ = *p++;
2694                 }
2695         }
2696
2697         assert( normalized->bv_val <= p );
2698         assert( q <= p );
2699
2700         /*
2701          * If the string ended in space, backup the pointer one
2702          * position.  One is enough because the above loop collapsed
2703          * all whitespace to a single space.
2704          */
2705         if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2706
2707         /* null terminate */
2708         *q = '\0';
2709
2710         normalized->bv_len = q - normalized->bv_val;
2711
2712         return LDAP_SUCCESS;
2713 }
2714
2715 static int
2716 UUIDValidate(
2717         Syntax *syntax,
2718         struct berval *in )
2719 {
2720         int i;
2721         if( in->bv_len != 36 ) {
2722                 return LDAP_INVALID_SYNTAX;
2723         }
2724
2725         for( i=0; i<36; i++ ) {
2726                 switch(i) {
2727                         case 8:
2728                         case 13:
2729                         case 18:
2730                         case 23:
2731                                 if( in->bv_val[i] != '-' ) {
2732                                         return LDAP_INVALID_SYNTAX;
2733                                 }
2734                                 break;
2735                         default:
2736                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2737                                         return LDAP_INVALID_SYNTAX;
2738                                 }
2739                 }
2740         }
2741         
2742         return LDAP_SUCCESS;
2743 }
2744
2745 static int
2746 UUIDPretty(
2747         Syntax *syntax,
2748         struct berval *in,
2749         struct berval *out,
2750         void *ctx )
2751 {
2752         int i;
2753         int rc=LDAP_INVALID_SYNTAX;
2754
2755         assert( in != NULL );
2756         assert( out != NULL );
2757
2758         if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2759
2760         out->bv_len = 36;
2761         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2762
2763         for( i=0; i<36; i++ ) {
2764                 switch(i) {
2765                         case 8:
2766                         case 13:
2767                         case 18:
2768                         case 23:
2769                                 if( in->bv_val[i] != '-' ) {
2770                                         goto handle_error;
2771                                 }
2772                                 out->bv_val[i] = '-';
2773                                 break;
2774
2775                         default:
2776                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2777                                         goto handle_error;
2778                                 }
2779                                 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2780                 }
2781         }
2782
2783         rc = LDAP_SUCCESS;
2784         out->bv_val[ out->bv_len ] = '\0';
2785
2786         if( 0 ) {
2787 handle_error:
2788                 slap_sl_free( out->bv_val, ctx );
2789                 out->bv_val = NULL;
2790         }
2791
2792         return rc;
2793 }
2794
2795 int
2796 UUIDNormalize(
2797         slap_mask_t usage,
2798         Syntax *syntax,
2799         MatchingRule *mr,
2800         struct berval *val,
2801         struct berval *normalized,
2802         void *ctx )
2803 {
2804         unsigned char octet = '\0';
2805         int i;
2806         int j;
2807
2808         if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
2809                 /* NOTE: must be a normalized UUID */
2810                 assert( val->bv_len == 16 );
2811
2812                 normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
2813                 normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
2814                         val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
2815                 assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
2816
2817                 return LDAP_SUCCESS;
2818         }
2819
2820         normalized->bv_len = 16;
2821         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2822
2823         for( i=0, j=0; i<36; i++ ) {
2824                 unsigned char nibble;
2825                 if( val->bv_val[i] == '-' ) {
2826                         continue;
2827
2828                 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2829                         nibble = val->bv_val[i] - '0';
2830
2831                 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2832                         nibble = val->bv_val[i] - ('a'-10);
2833
2834                 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2835                         nibble = val->bv_val[i] - ('A'-10);
2836
2837                 } else {
2838                         slap_sl_free( normalized->bv_val, ctx );
2839                         return LDAP_INVALID_SYNTAX;
2840                 }
2841
2842                 if( j & 1 ) {
2843                         octet |= nibble;
2844                         normalized->bv_val[j>>1] = octet;
2845                 } else {
2846                         octet = nibble << 4;
2847                 }
2848                 j++;
2849         }
2850
2851         normalized->bv_val[normalized->bv_len] = 0;
2852         return LDAP_SUCCESS;
2853 }
2854
2855
2856
2857 int
2858 numericStringValidate(
2859         Syntax *syntax,
2860         struct berval *in )
2861 {
2862         ber_len_t i;
2863
2864         if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2865
2866         for(i=0; i < in->bv_len; i++) {
2867                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2868                         return LDAP_INVALID_SYNTAX;
2869                 }
2870         }
2871
2872         return LDAP_SUCCESS;
2873 }
2874
2875 static int
2876 numericStringNormalize(
2877         slap_mask_t usage,
2878         Syntax *syntax,
2879         MatchingRule *mr,
2880         struct berval *val,
2881         struct berval *normalized,
2882         void *ctx )
2883 {
2884         /* removal all spaces */
2885         char *p, *q;
2886
2887         assert( !BER_BVISEMPTY( val ) );
2888
2889         normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2890
2891         p = val->bv_val;
2892         q = normalized->bv_val;
2893
2894         while ( *p ) {
2895                 if ( ASCII_SPACE( *p ) ) {
2896                         /* Ignore whitespace */
2897                         p++;
2898                 } else {
2899                         *q++ = *p++;
2900                 }
2901         }
2902
2903         /* we should have copied no more than is in val */
2904         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2905
2906         /* null terminate */
2907         *q = '\0';
2908
2909         normalized->bv_len = q - normalized->bv_val;
2910
2911         if( BER_BVISEMPTY( normalized ) ) {
2912                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2913                 normalized->bv_val[0] = ' ';
2914                 normalized->bv_val[1] = '\0';
2915                 normalized->bv_len = 1;
2916         }
2917
2918         return LDAP_SUCCESS;
2919 }
2920
2921 /*
2922  * Integer conversion macros that will use the largest available
2923  * type.
2924  */
2925 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
2926 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
2927 # define SLAP_LONG           long long
2928 #else
2929 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
2930 # define SLAP_LONG           long
2931 #endif /* HAVE_STRTOLL ... */
2932
2933 static int
2934 integerBitAndMatch(
2935         int *matchp,
2936         slap_mask_t flags,
2937         Syntax *syntax,
2938         MatchingRule *mr,
2939         struct berval *value,
2940         void *assertedValue )
2941 {
2942         SLAP_LONG lValue, lAssertedValue;
2943
2944         errno = 0;
2945         /* safe to assume integers are NUL terminated? */
2946         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2947         if( errno == ERANGE )
2948         {
2949                 return LDAP_CONSTRAINT_VIOLATION;
2950         }
2951
2952         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2953                 NULL, 10);
2954         if( errno == ERANGE )
2955         {
2956                 return LDAP_CONSTRAINT_VIOLATION;
2957         }
2958
2959         *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2960         return LDAP_SUCCESS;
2961 }
2962
2963 static int
2964 integerBitOrMatch(
2965         int *matchp,
2966         slap_mask_t flags,
2967         Syntax *syntax,
2968         MatchingRule *mr,
2969         struct berval *value,
2970         void *assertedValue )
2971 {
2972         SLAP_LONG lValue, lAssertedValue;
2973
2974         errno = 0;
2975         /* safe to assume integers are NUL terminated? */
2976         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2977         if( errno == ERANGE )
2978         {
2979                 return LDAP_CONSTRAINT_VIOLATION;
2980         }
2981
2982         lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2983                 NULL, 10);
2984         if( errno == ERANGE )
2985         {
2986                 return LDAP_CONSTRAINT_VIOLATION;
2987         }
2988
2989         *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2990         return LDAP_SUCCESS;
2991 }
2992
2993 static int
2994 checkNum( struct berval *in, struct berval *out )
2995 {
2996         /* parse serialNumber */
2997         ber_len_t neg = 0, extra = 0;
2998         char first = '\0';
2999
3000         out->bv_val = in->bv_val;
3001         out->bv_len = 0;
3002
3003         if ( out->bv_val[0] == '-' ) {
3004                 neg++;
3005                 out->bv_len++;
3006         }
3007
3008         if ( strncasecmp( out->bv_val, "0x", STRLENOF("0x") ) == 0 ) {
3009                 first = out->bv_val[2];
3010                 extra = 2;
3011
3012                 out->bv_len += STRLENOF("0x");
3013                 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3014                         if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3015                 }
3016
3017         } else if ( out->bv_val[0] == '\'' ) {
3018                 first = out->bv_val[1];
3019                 extra = 3;
3020
3021                 out->bv_len += STRLENOF("'");
3022
3023                 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3024                         if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3025                 }
3026                 if ( strncmp( &out->bv_val[out->bv_len], "'H", STRLENOF("'H") ) != 0 ) {
3027                         return -1;
3028                 }
3029                 out->bv_len += STRLENOF("'H");
3030
3031         } else {
3032                 first = out->bv_val[0];
3033                 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3034                         if ( !ASCII_DIGIT( out->bv_val[out->bv_len] ) ) break;
3035                 }
3036         }
3037
3038         if ( !( out->bv_len > neg ) ) {
3039                 return -1;
3040         }
3041
3042         if ( ( out->bv_len > extra + 1 + neg ) && ( first == '0' ) ) {
3043                 return -1;
3044         }
3045
3046         return 0;
3047 }
3048
3049 static int
3050 serialNumberAndIssuerCheck(
3051         struct berval *in,
3052         struct berval *sn,
3053         struct berval *is,
3054         void *ctx )
3055 {
3056         ber_len_t n;
3057
3058         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3059
3060         if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3061                 /* Parse old format */
3062                 is->bv_val = ber_bvchr( in, '$' );
3063                 if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
3064
3065                 sn->bv_val = in->bv_val;
3066                 sn->bv_len = is->bv_val - in->bv_val;
3067
3068                 is->bv_val++;
3069                 is->bv_len = in->bv_len - (sn->bv_len + 1);
3070
3071                 /* eat leading zeros */
3072                 for( n=0; n < (sn->bv_len-1); n++ ) {
3073                         if( sn->bv_val[n] != '0' ) break;
3074                 }
3075                 sn->bv_val += n;
3076                 sn->bv_len -= n;
3077
3078                 for( n=0; n < sn->bv_len; n++ ) {
3079                         if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3080                 }
3081
3082         } else {
3083                 /* Parse GSER format */ 
3084                 enum {
3085                         HAVE_NONE = 0x0,
3086                         HAVE_ISSUER = 0x1,
3087                         HAVE_SN = 0x2,
3088                         HAVE_ALL = ( HAVE_ISSUER | HAVE_SN )
3089                 } have = HAVE_NONE;
3090
3091                 int numdquotes = 0;
3092                 struct berval x = *in;
3093                 struct berval ni;
3094                 x.bv_val++;
3095                 x.bv_len -= 2;
3096
3097                 do {
3098                         /* eat leading spaces */
3099                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3100                                 /* empty */;
3101                         }
3102
3103                         /* should be at issuer or serialNumber NamedValue */
3104                         if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3105                                 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3106
3107                                 /* parse issuer */
3108                                 x.bv_val += STRLENOF("issuer");
3109                                 x.bv_len -= STRLENOF("issuer");
3110
3111                                 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3112                                 x.bv_val++;
3113                                 x.bv_len--;
3114
3115                                 /* eat leading spaces */
3116                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3117                                         /* empty */;
3118                                 }
3119
3120                                 /* For backward compatibility, this part is optional */
3121                                 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) == 0 ) {
3122                                         x.bv_val += STRLENOF("rdnSequence:");
3123                                         x.bv_len -= STRLENOF("rdnSequence:");
3124                                 }
3125
3126                                 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3127                                 x.bv_val++;
3128                                 x.bv_len--;
3129
3130                                 is->bv_val = x.bv_val;
3131                                 is->bv_len = 0;
3132
3133                                 for ( ; is->bv_len < x.bv_len; ) {
3134                                         if ( is->bv_val[is->bv_len] != '"' ) {
3135                                                 is->bv_len++;
3136                                                 continue;
3137                                         }
3138                                         if ( is->bv_val[is->bv_len+1] == '"' ) {
3139                                                 /* double dquote */
3140                                                 is->bv_len += 2;
3141                                                 continue;
3142                                         }
3143                                         break;
3144                                 }
3145                                 x.bv_val += is->bv_len + 1;
3146                                 x.bv_len -= is->bv_len + 1;
3147
3148                                 have |= HAVE_ISSUER;
3149
3150                         } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 )
3151                         {
3152                                 if ( have & HAVE_SN ) return LDAP_INVALID_SYNTAX;
3153
3154                                 /* parse serialNumber */
3155                                 x.bv_val += STRLENOF("serialNumber");
3156                                 x.bv_len -= STRLENOF("serialNumber");
3157
3158                                 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3159                                 x.bv_val++;
3160                                 x.bv_len--;
3161
3162                                 /* eat leading spaces */
3163                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3164                                         /* empty */;
3165                                 }
3166
3167                                 if ( checkNum( &x, sn ) ) {
3168                                         return LDAP_INVALID_SYNTAX;
3169                                 }
3170
3171                                 x.bv_val += sn->bv_len;
3172                                 x.bv_len -= sn->bv_len;
3173
3174                                 have |= HAVE_SN;
3175
3176                         } else {
3177                                 return LDAP_INVALID_SYNTAX;
3178                         }
3179
3180                         /* eat leading spaces */
3181                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3182                                 /* empty */;
3183                         }
3184
3185                         if ( have == HAVE_ALL ) {
3186                                 break;
3187                         }
3188
3189                         if ( x.bv_val[0] != ',' ) {
3190                                 return LDAP_INVALID_SYNTAX;
3191                         }
3192
3193                         x.bv_val++;
3194                         x.bv_len--;
3195                 } while ( 1 );
3196
3197                 /* should have no characters left... */
3198                 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3199
3200                 if ( numdquotes == 0 ) {
3201                         ber_dupbv_x( &ni, is, ctx );
3202
3203                 } else {
3204                         ber_len_t src, dst;
3205
3206                         ni.bv_len = is->bv_len - numdquotes;
3207                         ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3208                         for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3209                                 if ( is->bv_val[src] == '"' ) {
3210                                         src++;
3211                                 }
3212                                 ni.bv_val[dst] = is->bv_val[src];
3213                         }
3214                         ni.bv_val[dst] = '\0';
3215                 }
3216                         
3217                 *is = ni;
3218         }
3219
3220         return 0;
3221 }
3222         
3223 static int
3224 serialNumberAndIssuerValidate(
3225         Syntax *syntax,
3226         struct berval *in )
3227 {
3228         int rc;
3229         struct berval sn, i;
3230
3231         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3232                 in->bv_val, 0, 0 );
3233
3234         rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3235         if ( rc ) {
3236                 goto done;
3237         }
3238
3239         /* validate DN -- doesn't handle double dquote */ 
3240         rc = dnValidate( NULL, &i );
3241         if ( rc ) {
3242                 rc = LDAP_INVALID_SYNTAX;
3243         }
3244
3245         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3246                 slap_sl_free( i.bv_val, NULL );
3247         }
3248
3249         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: <%s> err=%d\n",
3250                 in->bv_val, rc, 0 );
3251
3252 done:;
3253         return rc;
3254 }
3255
3256 static int
3257 serialNumberAndIssuerPretty(
3258         Syntax *syntax,
3259         struct berval *in,
3260         struct berval *out,
3261         void *ctx )
3262 {
3263         int rc;
3264         struct berval sn, i, ni = BER_BVNULL;
3265         char *p;
3266
3267         assert( in != NULL );
3268         assert( out != NULL );
3269
3270         BER_BVZERO( out );
3271
3272         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3273                 in->bv_val, 0, 0 );
3274
3275         rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3276         if ( rc ) {
3277                 goto done;
3278         }
3279
3280         rc = dnPretty( syntax, &i, &ni, ctx );
3281
3282         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3283                 slap_sl_free( i.bv_val, ctx );
3284         }
3285
3286         if ( rc ) {
3287                 rc = LDAP_INVALID_SYNTAX;
3288                 goto done;
3289         }
3290
3291         /* make room from sn + "$" */
3292         out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3293                 + sn.bv_len + ni.bv_len;
3294         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3295
3296         if ( out->bv_val == NULL ) {
3297                 out->bv_len = 0;
3298                 rc = LDAP_OTHER;
3299                 goto done;
3300         }
3301
3302         p = out->bv_val;
3303         p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3304         p = lutil_strncopy( p, sn.bv_val, sn.bv_len );
3305         p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3306         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
3307         p = lutil_strcopy( p, /*{*/ "\" }" );
3308
3309         assert( p == &out->bv_val[out->bv_len] );
3310
3311 done:;
3312         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s> => <%s>\n",
3313                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3314
3315         slap_sl_free( ni.bv_val, ctx );
3316
3317         return LDAP_SUCCESS; 
3318 }
3319
3320 static int
3321 slap_bin2hex(
3322         struct berval *in,
3323         struct berval *out,
3324         void *ctx )
3325
3326 {       
3327         /* Use hex format. '123456789abcdef'H */
3328         unsigned char *ptr, zero = '\0';
3329         char *sptr;
3330         int first;
3331         ber_len_t i, len, nlen;
3332
3333         assert( in != NULL );
3334         assert( !BER_BVISNULL( in ) );
3335         assert( out != NULL );
3336         assert( !BER_BVISNULL( out ) );
3337
3338         ptr = (unsigned char *)in->bv_val;
3339         len = in->bv_len;
3340
3341         /* Check for minimal encodings */
3342         if ( len > 1 ) {
3343                 if ( ptr[0] & 0x80 ) {
3344                         if ( ( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ) ) {
3345                                 return -1;
3346                         }
3347
3348                 } else if ( ptr[0] == 0 ) {
3349                         if ( !( ptr[1] & 0x80 ) ) {
3350                                 return -1;
3351                         }
3352                         len--;
3353                         ptr++;
3354                 }
3355
3356         } else if ( len == 0 ) {
3357                 /* FIXME: this should not be possible,
3358                  * since a value of zero would have length 1 */
3359                 len = 1;
3360                 ptr = &zero;
3361         }
3362
3363         first = !( ptr[0] & 0xf0U );
3364         nlen = len * 2 - first + STRLENOF("''H"); /* quotes, H */
3365         if ( nlen >= out->bv_len ) {
3366                 out->bv_val = slap_sl_malloc( nlen + 1, ctx );
3367         }
3368         sptr = out->bv_val;
3369         *sptr++ = '\'';
3370         i = 0;
3371         if ( first ) {
3372                 sprintf( sptr, "%01X", ( ptr[0] & 0x0fU ) );
3373                 sptr++;
3374                 i = 1;
3375         }
3376         for ( ; i < len; i++ ) {
3377                 sprintf( sptr, "%02X", ptr[i] );
3378                 sptr += 2;
3379         }
3380         *sptr++ = '\'';
3381         *sptr++ = 'H';
3382         *sptr = '\0';
3383
3384         assert( sptr == &out->bv_val[nlen] );
3385
3386         out->bv_len = nlen;
3387
3388         return 0;
3389 }
3390
3391 #define SLAP_SN_BUFLEN  (64)
3392
3393 /*
3394  * This routine is called by certificateExactNormalize when
3395  * certificateExactNormalize receives a search string instead of
3396  * a certificate. This routine checks if the search value is valid
3397  * and then returns the normalized value
3398  */
3399 static int
3400 serialNumberAndIssuerNormalize(
3401         slap_mask_t usage,
3402         Syntax *syntax,
3403         MatchingRule *mr,
3404         struct berval *in,
3405         struct berval *out,
3406         void *ctx )
3407 {
3408         struct berval sn, sn2, sn3, i, ni;
3409         char sbuf2[SLAP_SN_BUFLEN];
3410         char sbuf3[SLAP_SN_BUFLEN];
3411         char *p;
3412         int rc;
3413
3414         assert( in != NULL );
3415         assert( out != NULL );
3416
3417         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3418                 in->bv_val, 0, 0 );
3419
3420         rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3421         if ( rc ) {
3422                 return rc;
3423         }
3424
3425         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3426
3427         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3428                 slap_sl_free( i.bv_val, ctx );
3429         }
3430
3431         if ( rc ) {
3432                 return LDAP_INVALID_SYNTAX;
3433         }
3434
3435         /* Convert sn to canonical hex */
3436         sn2.bv_val = sbuf2;
3437         if ( sn.bv_len > sizeof( sbuf2 ) ) {
3438                 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
3439         }
3440         sn2.bv_len = sn.bv_len;
3441         if ( lutil_str2bin( &sn, &sn2, ctx )) {
3442                 rc = LDAP_INVALID_SYNTAX;
3443                 goto func_leave;
3444         }
3445
3446         sn3.bv_val = sbuf3;
3447         sn3.bv_len = sizeof(sbuf3);
3448         if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
3449                 rc = LDAP_INVALID_SYNTAX;
3450                 goto func_leave;
3451         }
3452
3453         out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3454                 + sn3.bv_len + ni.bv_len;
3455         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3456
3457         if ( out->bv_val == NULL ) {
3458                 out->bv_len = 0;
3459                 rc = LDAP_OTHER;
3460                 goto func_leave;
3461         }
3462
3463         p = out->bv_val;
3464
3465         p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3466         p = lutil_strncopy( p, sn3.bv_val, sn3.bv_len );
3467         p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3468         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
3469         p = lutil_strcopy( p, /*{*/ "\" }" );
3470
3471         assert( p == &out->bv_val[out->bv_len] );
3472
3473 func_leave:
3474         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n",
3475                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3476
3477         if ( sn2.bv_val != sbuf2 ) {
3478                 slap_sl_free( sn2.bv_val, ctx );
3479         }
3480
3481         if ( sn3.bv_val != sbuf3 ) {
3482                 slap_sl_free( sn3.bv_val, ctx );
3483         }
3484
3485         slap_sl_free( ni.bv_val, ctx );
3486
3487         return rc;
3488 }
3489
3490 static int
3491 certificateExactNormalize(
3492         slap_mask_t usage,
3493         Syntax *syntax,
3494         MatchingRule *mr,
3495         struct berval *val,
3496         struct berval *normalized,
3497         void *ctx )
3498 {
3499         BerElementBuffer berbuf;
3500         BerElement *ber = (BerElement *)&berbuf;
3501         ber_tag_t tag;
3502         ber_len_t len;
3503         ber_int_t i;
3504         char serialbuf2[SLAP_SN_BUFLEN];
3505         struct berval sn, sn2 = BER_BVNULL;
3506         struct berval issuer_dn = BER_BVNULL, bvdn;
3507         char *p;
3508         int rc = LDAP_INVALID_SYNTAX;
3509
3510         assert( val != NULL );
3511
3512         Debug( LDAP_DEBUG_TRACE, ">>> certificateExactNormalize: <%p, %lu>\n",
3513                 val->bv_val, val->bv_len, 0 );
3514
3515         if ( BER_BVISEMPTY( val ) ) goto done;
3516
3517         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3518                 return serialNumberAndIssuerNormalize( 0, NULL, NULL, val, normalized, ctx );
3519         }
3520
3521         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3522
3523         ber_init2( ber, val, LBER_USE_DER );
3524         tag = ber_skip_tag( ber, &len );        /* Signed Sequence */
3525         tag = ber_skip_tag( ber, &len );        /* Sequence */
3526         tag = ber_peek_tag( ber, &len );        /* Optional version? */
3527         if ( tag == SLAP_X509_OPT_C_VERSION ) {
3528                 tag = ber_skip_tag( ber, &len );
3529                 tag = ber_get_int( ber, &i );   /* version */
3530         }
3531
3532         /* NOTE: move the test here from certificateValidate,
3533          * so that we can validate certs with serial longer
3534          * than sizeof(ber_int_t) */
3535         tag = ber_skip_tag( ber, &len );        /* serial */
3536         sn.bv_len = len;
3537         sn.bv_val = (char *)ber->ber_ptr;
3538         sn2.bv_val = serialbuf2;
3539         sn2.bv_len = sizeof(serialbuf2);
3540         if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
3541                 rc = LDAP_INVALID_SYNTAX;
3542                 goto done;
3543         }
3544         ber_skip_data( ber, len );
3545
3546         tag = ber_skip_tag( ber, &len );        /* SignatureAlg */
3547         ber_skip_data( ber, len );
3548         tag = ber_peek_tag( ber, &len );        /* IssuerDN */
3549         len = ber_ptrlen( ber );
3550         bvdn.bv_val = val->bv_val + len;
3551         bvdn.bv_len = val->bv_len - len;
3552
3553         rc = dnX509normalize( &bvdn, &issuer_dn );
3554         if ( rc != LDAP_SUCCESS ) goto done;
3555
3556         normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3557                 + sn2.bv_len + issuer_dn.bv_len;
3558         normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
3559
3560         p = normalized->bv_val;
3561
3562         p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3563         p = lutil_strncopy( p, sn2.bv_val, sn2.bv_len );
3564         p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3565         p = lutil_strncopy( p, issuer_dn.bv_val, issuer_dn.bv_len );
3566         p = lutil_strcopy( p, /*{*/ "\" }" );
3567
3568         rc = LDAP_SUCCESS;
3569
3570 done:
3571         Debug( LDAP_DEBUG_TRACE, "<<< certificateExactNormalize: <%p, %lu> => <%s>\n",
3572                 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
3573
3574         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3575         if ( sn2.bv_val != serialbuf2 ) ber_memfree_x( sn2.bv_val, ctx );
3576
3577         return rc;
3578 }
3579
3580 /* X.509 PKI certificateList stuff */
3581 static int
3582 checkTime( struct berval *in, struct berval *out )
3583 {
3584         int rc;
3585         ber_len_t i;
3586         char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3587         struct berval bv;
3588
3589         assert( in != NULL );
3590         assert( !BER_BVISNULL( in ) );
3591         assert( !BER_BVISEMPTY( in ) );
3592
3593         if ( in->bv_len < STRLENOF( "YYmmddHHMMSSZ" ) ) {
3594                 return -1;
3595         }
3596
3597         if ( out != NULL ) {
3598                 assert( !BER_BVISNULL( out ) );
3599                 assert( out->bv_len >= sizeof( buf ) );
3600                 bv.bv_val = out->bv_val;
3601
3602         } else {
3603                 bv.bv_val = buf;
3604         }
3605
3606         for ( i = 0; i < STRLENOF( "YYYYmmddHHMMSS" ); i++ ) {
3607                 if ( !ASCII_DIGIT( in->bv_val[i] ) ) break;
3608         }
3609
3610         if ( in->bv_val[i] != 'Z' ) {
3611                 return -1;
3612         }
3613         i++;
3614
3615         if ( i != in->bv_len ) {
3616                 return -1;
3617         }
3618
3619         if ( i == STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3620                 lutil_strncopy( bv.bv_val, in->bv_val, i );
3621                 bv.bv_len = i;
3622                 
3623         } else if ( i == STRLENOF( "YYmmddHHMMSSZ" ) ) {
3624                 char *p = bv.bv_val;
3625                 if ( in->bv_val[0] < '7' ) {
3626                         p = lutil_strcopy( p, "20" );
3627
3628                 } else {
3629                         p = lutil_strcopy( p, "19" );
3630                 }
3631                 lutil_strncopy( p, in->bv_val, i );
3632                 bv.bv_len = 2 + i;
3633
3634         } else {
3635                 return -1;
3636         }
3637
3638         rc = generalizedTimeValidate( NULL, &bv );
3639         if ( rc == LDAP_SUCCESS && out != NULL ) {
3640                 out->bv_len = bv.bv_len;
3641         }
3642
3643         return rc != LDAP_SUCCESS;
3644 }
3645
3646 static int
3647 issuerAndThisUpdateCheck(
3648         struct berval *in,
3649         struct berval *is,
3650         struct berval *tu,
3651         void *ctx )
3652 {
3653         int numdquotes = 0;
3654         struct berval x = *in;
3655         struct berval ni = BER_BVNULL;
3656         /* Parse GSER format */ 
3657         enum {
3658                 HAVE_NONE = 0x0,
3659                 HAVE_ISSUER = 0x1,
3660                 HAVE_THISUPDATE = 0x2,
3661                 HAVE_ALL = ( HAVE_ISSUER | HAVE_THISUPDATE )
3662         } have = HAVE_NONE;
3663
3664
3665         if ( in->bv_len < STRLENOF( "{issuer \"\",thisUpdate \"YYMMDDhhmmssZ\"}" ) ) return LDAP_INVALID_SYNTAX;
3666
3667         if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3668                 return LDAP_INVALID_SYNTAX;
3669         }
3670
3671         x.bv_val++;
3672         x.bv_len -= STRLENOF("{}");
3673
3674         do {
3675                 /* eat leading spaces */
3676                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3677                         /* empty */;
3678                 }
3679
3680                 /* should be at issuer or thisUpdate */
3681                 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3682                         if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3683
3684                         /* parse issuer */
3685                         x.bv_val += STRLENOF("issuer");
3686                         x.bv_len -= STRLENOF("issuer");
3687
3688                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3689                         x.bv_val++;
3690                         x.bv_len--;
3691
3692                         /* eat leading spaces */
3693                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3694                                 /* empty */;
3695                         }
3696
3697                         /* For backward compatibility, this part is optional */
3698                         if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) != 0 ) {
3699                                 return LDAP_INVALID_SYNTAX;
3700                         }
3701                         x.bv_val += STRLENOF("rdnSequence:");
3702                         x.bv_len -= STRLENOF("rdnSequence:");
3703
3704                         if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3705                         x.bv_val++;
3706                         x.bv_len--;
3707
3708                         is->bv_val = x.bv_val;
3709                         is->bv_len = 0;
3710
3711                         for ( ; is->bv_len < x.bv_len; ) {
3712                                 if ( is->bv_val[is->bv_len] != '"' ) {
3713                                         is->bv_len++;
3714                                         continue;
3715                                 }
3716                                 if ( is->bv_val[is->bv_len+1] == '"' ) {
3717                                         /* double dquote */
3718                                         is->bv_len += 2;
3719                                         continue;
3720                                 }
3721                                 break;
3722                         }
3723                         x.bv_val += is->bv_len + 1;
3724                         x.bv_len -= is->bv_len + 1;
3725
3726                         have |= HAVE_ISSUER;
3727
3728                 } else if ( strncasecmp( x.bv_val, "thisUpdate", STRLENOF("thisUpdate") ) == 0 )
3729                 {
3730                         if ( have & HAVE_THISUPDATE ) return LDAP_INVALID_SYNTAX;
3731
3732                         /* parse thisUpdate */
3733                         x.bv_val += STRLENOF("thisUpdate");
3734                         x.bv_len -= STRLENOF("thisUpdate");
3735
3736                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3737                         x.bv_val++;
3738                         x.bv_len--;
3739
3740                         /* eat leading spaces */
3741                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3742                                 /* empty */;
3743                         }
3744
3745                         if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3746                         x.bv_val++;
3747                         x.bv_len--;
3748
3749                         tu->bv_val = x.bv_val;
3750                         tu->bv_len = 0;
3751
3752                         for ( ; tu->bv_len < x.bv_len; tu->bv_len++ ) {
3753                                 if ( tu->bv_val[tu->bv_len] == '"' ) {
3754                                         break;
3755                                 }
3756                         }
3757                         x.bv_val += tu->bv_len + 1;
3758                         x.bv_len -= tu->bv_len + 1;
3759
3760                         have |= HAVE_THISUPDATE;
3761
3762                 } else {
3763                         return LDAP_INVALID_SYNTAX;
3764                 }
3765
3766                 /* eat leading spaces */
3767                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3768                         /* empty */;
3769                 }
3770
3771                 if ( have == HAVE_ALL ) {
3772                         break;
3773                 }
3774
3775                 if ( x.bv_val[0] != ',' ) {
3776                         return LDAP_INVALID_SYNTAX;
3777                 }
3778
3779                 x.bv_val++;
3780                 x.bv_len--;
3781         } while ( 1 );
3782
3783         /* should have no characters left... */
3784         if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3785
3786         if ( numdquotes == 0 ) {
3787                 ber_dupbv_x( &ni, is, ctx );
3788
3789         } else {
3790                 ber_len_t src, dst;
3791
3792                 ni.bv_len = is->bv_len - numdquotes;
3793                 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3794                 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3795                         if ( is->bv_val[src] == '"' ) {
3796                                 src++;
3797                         }
3798                         ni.bv_val[dst] = is->bv_val[src];
3799                 }
3800                 ni.bv_val[dst] = '\0';
3801         }
3802                 
3803         *is = ni;
3804
3805         return 0;
3806 }
3807
3808 static int
3809 issuerAndThisUpdateValidate(
3810         Syntax *syntax,
3811         struct berval *in )
3812 {
3813         int rc;
3814         struct berval i, tu;
3815
3816         Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateValidate: <%s>\n",
3817                 in->bv_val, 0, 0 );
3818
3819         rc = issuerAndThisUpdateCheck( in, &i, &tu, NULL );
3820         if ( rc ) {
3821                 goto done;
3822         }
3823
3824         /* validate DN -- doesn't handle double dquote */ 
3825         rc = dnValidate( NULL, &i );
3826         if ( rc ) {
3827                 rc = LDAP_INVALID_SYNTAX;
3828
3829         } else if ( checkTime( &tu, NULL ) ) {
3830                 rc = LDAP_INVALID_SYNTAX;
3831         }
3832
3833         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3834                 slap_sl_free( i.bv_val, NULL );
3835         }
3836
3837         Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateValidate: <%s> err=%d\n",
3838                 in->bv_val, rc, 0 );
3839
3840 done:;
3841         return rc;
3842 }
3843
3844 static int
3845 issuerAndThisUpdatePretty(
3846         Syntax *syntax,
3847         struct berval *in,
3848         struct berval *out,
3849         void *ctx )
3850 {
3851         int rc;
3852         struct berval i, tu, ni = BER_BVNULL;
3853         char *p;
3854
3855         assert( in != NULL );
3856         assert( out != NULL );
3857
3858         BER_BVZERO( out );
3859
3860         Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdatePretty: <%s>\n",
3861                 in->bv_val, 0, 0 );
3862
3863         rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
3864         if ( rc ) {
3865                 goto done;
3866         }
3867
3868         rc = dnPretty( syntax, &i, &ni, ctx );
3869
3870         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3871                 slap_sl_free( i.bv_val, ctx );
3872         }
3873
3874         if ( rc || checkTime( &tu, NULL ) ) {
3875                 rc = LDAP_INVALID_SYNTAX;
3876                 goto done;
3877         }
3878
3879         /* make room */
3880         out->bv_len = STRLENOF("{ issuer rdnSequence:\"\", thisUpdate \"\" }")
3881                 + ni.bv_len + tu.bv_len;
3882         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3883
3884         if ( out->bv_val == NULL ) {
3885                 out->bv_len = 0;
3886                 rc = LDAP_OTHER;
3887                 goto done;
3888         }
3889
3890         p = out->bv_val;
3891         p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
3892         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
3893         p = lutil_strcopy( p, "\", thisUpdate \"" );
3894         p = lutil_strncopy( p, tu.bv_val, tu.bv_len );
3895         p = lutil_strcopy( p, /*{*/ "\" }" );
3896
3897         assert( p == &out->bv_val[out->bv_len] );
3898
3899 done:;
3900         Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n",
3901                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3902
3903         slap_sl_free( ni.bv_val, ctx );
3904
3905         return rc; 
3906 }
3907
3908 static int
3909 issuerAndThisUpdateNormalize(
3910         slap_mask_t usage,
3911         Syntax *syntax,
3912         MatchingRule *mr,
3913         struct berval *in,
3914         struct berval *out,
3915         void *ctx )
3916 {
3917         struct berval i, ni, tu, tu2;
3918         char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3919         char *p;
3920         int rc;
3921
3922         assert( in != NULL );
3923         assert( out != NULL );
3924
3925         Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
3926                 in->bv_val, 0, 0 );
3927
3928         rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
3929         if ( rc ) {
3930                 return rc;
3931         }
3932
3933         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3934
3935         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3936                 slap_sl_free( i.bv_val, ctx );
3937         }
3938
3939         tu2.bv_val = sbuf;
3940         tu2.bv_len = sizeof( sbuf );
3941         if ( rc || checkTime( &tu, &tu2 ) ) {
3942                 return LDAP_INVALID_SYNTAX;
3943         }
3944
3945         out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
3946                 + ni.bv_len + tu2.bv_len;
3947         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3948
3949         if ( out->bv_val == NULL ) {
3950                 out->bv_len = 0;
3951                 rc = LDAP_OTHER;
3952                 goto func_leave;
3953         }
3954
3955         p = out->bv_val;
3956
3957         p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
3958         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
3959         p = lutil_strcopy( p, "\", thisUpdate \"" );
3960         p = lutil_strncopy( p, tu2.bv_val, tu2.bv_len );
3961         p = lutil_strcopy( p, /*{*/ "\" }" );
3962
3963         assert( p == &out->bv_val[out->bv_len] );
3964
3965 func_leave:
3966         Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
3967                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3968
3969         slap_sl_free( ni.bv_val, ctx );
3970
3971         return rc;
3972 }
3973
3974 static int
3975 certificateListExactNormalize(
3976         slap_mask_t usage,
3977         Syntax *syntax,
3978         MatchingRule *mr,
3979         struct berval *val,
3980         struct berval *normalized,
3981         void *ctx )
3982 {
3983         BerElementBuffer berbuf;
3984         BerElement *ber = (BerElement *)&berbuf;
3985         ber_tag_t tag;
3986         ber_len_t len;
3987         ber_int_t version;
3988         struct berval issuer_dn = BER_BVNULL, bvdn,
3989                 thisUpdate, bvtu;
3990         char *p, tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3991         int rc = LDAP_INVALID_SYNTAX;
3992
3993         assert( val != NULL );
3994
3995         Debug( LDAP_DEBUG_TRACE, ">>> certificateListExactNormalize: <%p, %lu>\n",
3996                 val->bv_val, val->bv_len, 0 );
3997
3998         if ( BER_BVISEMPTY( val ) ) goto done;
3999
4000         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4001                 return issuerAndThisUpdateNormalize( 0, NULL, NULL, val, normalized, ctx );
4002         }
4003
4004         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4005
4006         ber_init2( ber, val, LBER_USE_DER );
4007         tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
4008         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4009         tag = ber_skip_tag( ber, &len );        /* Sequence */
4010         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4011         tag = ber_peek_tag( ber, &len );
4012         /* Optional version */
4013         if ( tag == LBER_INTEGER ) {
4014                 tag = ber_get_int( ber, &version );
4015                 assert( tag == LBER_INTEGER );
4016                 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
4017         }
4018         tag = ber_skip_tag( ber, &len );        /* Signature Algorithm */
4019         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4020         ber_skip_data( ber, len );
4021
4022         tag = ber_peek_tag( ber, &len );        /* IssuerDN */
4023         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4024         len = ber_ptrlen( ber );
4025         bvdn.bv_val = val->bv_val + len;
4026         bvdn.bv_len = val->bv_len - len;
4027         tag = ber_skip_tag( ber, &len );
4028         ber_skip_data( ber, len );
4029
4030         tag = ber_skip_tag( ber, &len );        /* thisUpdate */
4031         /* Time is a CHOICE { UTCTime, GeneralizedTime } */
4032         if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
4033         bvtu.bv_val = (char *)ber->ber_ptr;
4034         bvtu.bv_len = len;
4035
4036         rc = dnX509normalize( &bvdn, &issuer_dn );
4037         if ( rc != LDAP_SUCCESS ) goto done;
4038
4039         thisUpdate.bv_val = tubuf;
4040         thisUpdate.bv_len = sizeof(tubuf);
4041         if ( checkTime( &bvtu, &thisUpdate ) ) {
4042                 rc = LDAP_INVALID_SYNTAX;
4043                 goto done;
4044         }
4045
4046         normalized->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4047                 + issuer_dn.bv_len + thisUpdate.bv_len;
4048         normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4049
4050         p = normalized->bv_val;
4051
4052         p = lutil_strcopy( p, "{ issuer rdnSequence:\"" );
4053         p = lutil_strncopy( p, issuer_dn.bv_val, issuer_dn.bv_len );
4054         p = lutil_strcopy( p, "\", thisUpdate \"" );
4055         p = lutil_strncopy( p, thisUpdate.bv_val, thisUpdate.bv_len );
4056         p = lutil_strcopy( p, /*{*/ "\" }" );
4057
4058         rc = LDAP_SUCCESS;
4059
4060 done:
4061         Debug( LDAP_DEBUG_TRACE, "<<< certificateListExactNormalize: <%p, %lu> => <%s>\n",
4062                 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
4063
4064         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4065
4066         return rc;
4067 }
4068
4069 /* X.509 PMI serialNumberAndIssuerSerialCheck
4070
4071 AttributeCertificateExactAssertion     ::= SEQUENCE {
4072    serialNumber              CertificateSerialNumber,
4073    issuer                    AttCertIssuer }
4074
4075 CertificateSerialNumber ::= INTEGER
4076
4077 AttCertIssuer ::=    [0] SEQUENCE {
4078 issuerName                     GeneralNames OPTIONAL,
4079 baseCertificateID         [0] IssuerSerial OPTIONAL,
4080 objectDigestInfo          [1] ObjectDigestInfo OPTIONAL }
4081 -- At least one component shall be present
4082
4083 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
4084
4085 GeneralName ::= CHOICE {
4086   otherName                 [0] INSTANCE OF OTHER-NAME,
4087   rfc822Name                [1] IA5String,
4088   dNSName                   [2] IA5String,
4089   x400Address               [3] ORAddress,
4090   directoryName             [4] Name,
4091   ediPartyName              [5] EDIPartyName,
4092   uniformResourceIdentifier [6] IA5String,
4093   iPAddress                 [7] OCTET STRING,
4094   registeredID              [8] OBJECT IDENTIFIER }
4095
4096 IssuerSerial ::= SEQUENCE {
4097    issuer       GeneralNames,
4098    serial       CertificateSerialNumber,
4099    issuerUID UniqueIdentifier OPTIONAL }
4100
4101 ObjectDigestInfo ::= SEQUENCE {
4102    digestedObjectType ENUMERATED {
4103       publicKey           (0),
4104       publicKeyCert       (1),
4105       otherObjectTypes    (2) },
4106    otherObjectTypeID      OBJECT IDENTIFIER OPTIONAL,
4107    digestAlgorithm        AlgorithmIdentifier,
4108    objectDigest           BIT STRING }
4109
4110  * The way I interpret it, an assertion should look like
4111
4112  { serialNumber 'dd'H,
4113    issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional
4114             baseCertificateID { serial '1d'H,
4115                                 issuer { directoryName:rdnSequence:"cn=zzz" },
4116                                 issuerUID <value>              -- optional
4117                               },                               -- optional
4118             objectDigestInfo { ... }                           -- optional
4119           }
4120  }
4121  
4122  * with issuerName, baseCertificateID and objectDigestInfo optional,
4123  * at least one present; the way it's currently implemented, it is
4124
4125  { serialNumber 'dd'H,
4126    issuer { baseCertificateID { serial '1d'H,
4127                                 issuer { directoryName:rdnSequence:"cn=zzz" }
4128                               }
4129           }
4130  }
4131
4132  * with all the above parts mandatory.
4133  */
4134 static int
4135 serialNumberAndIssuerSerialCheck(
4136         struct berval *in,
4137         struct berval *sn,
4138         struct berval *is,
4139         struct berval *i_sn,    /* contain serial of baseCertificateID */
4140         void *ctx )
4141 {
4142         /* Parse GSER format */ 
4143         enum {
4144                 HAVE_NONE = 0x0,
4145                 HAVE_SN = 0x1,
4146                 HAVE_ISSUER = 0x2,
4147                 HAVE_ALL = ( HAVE_SN | HAVE_ISSUER )
4148         } have = HAVE_NONE, have2 = HAVE_NONE;
4149         int numdquotes = 0;
4150         struct berval x = *in;
4151         struct berval ni;
4152
4153         if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4154
4155         /* no old format */
4156         if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX;
4157
4158         x.bv_val++;
4159         x.bv_len -= 2;
4160
4161         do {
4162
4163                 /* eat leading spaces */
4164                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4165                         /* empty */;
4166                 }
4167
4168                 /* should be at issuer or serialNumber NamedValue */
4169                 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
4170                         if ( have & HAVE_ISSUER ) {
4171                                 return LDAP_INVALID_SYNTAX;
4172                         }
4173
4174                         /* parse IssuerSerial */
4175                         x.bv_val += STRLENOF("issuer");
4176                         x.bv_len -= STRLENOF("issuer");
4177
4178                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4179                         x.bv_val++;
4180                         x.bv_len--;
4181
4182                         /* eat leading spaces */
4183                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4184                                 /* empty */;
4185                         }
4186
4187                         if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4188                         x.bv_val++;
4189                         x.bv_len--;
4190
4191                         /* eat leading spaces */
4192                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4193                                 /* empty */;
4194                         }
4195
4196                         if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) {
4197                                 return LDAP_INVALID_SYNTAX;
4198                         }
4199                         x.bv_val += STRLENOF("baseCertificateID ");
4200                         x.bv_len -= STRLENOF("baseCertificateID ");
4201
4202                         /* eat leading spaces */
4203                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4204                                 /* empty */;
4205                         }
4206
4207                         if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4208                         x.bv_val++;
4209                         x.bv_len--;
4210
4211                         do {
4212                                 /* eat leading spaces */
4213                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4214                                         /* empty */;
4215                                 }
4216
4217                                 /* parse issuer of baseCertificateID */
4218                                 if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) {
4219                                         if ( have2 & HAVE_ISSUER ) {
4220                                                 return LDAP_INVALID_SYNTAX;
4221                                         }
4222
4223                                         x.bv_val += STRLENOF("issuer ");
4224                                         x.bv_len -= STRLENOF("issuer ");
4225
4226                                         /* eat leading spaces */
4227                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4228                                                 /* empty */;
4229                                         }
4230
4231                                         if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4232                                         x.bv_val++;
4233                                         x.bv_len--;
4234
4235                                         /* eat leading spaces */
4236                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4237                                                 /* empty */;
4238                                         }
4239
4240                                         if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) {
4241                                                 return LDAP_INVALID_SYNTAX;
4242                                         }
4243                                         x.bv_val += STRLENOF("directoryName:rdnSequence:");
4244                                         x.bv_len -= STRLENOF("directoryName:rdnSequence:");
4245
4246                                         if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
4247                                         x.bv_val++;
4248                                         x.bv_len--;
4249
4250                                         is->bv_val = x.bv_val;
4251                                         is->bv_len = 0;
4252
4253                                         for ( ; is->bv_len < x.bv_len; ) {
4254                                                 if ( is->bv_val[is->bv_len] != '"' ) {
4255                                                         is->bv_len++;
4256                                                         continue;
4257                                                 }
4258                                                 if ( is->bv_val[is->bv_len + 1] == '"' ) {
4259                                                         /* double dquote */
4260                                                         is->bv_len += 2;
4261                                                         continue;
4262                                                 }
4263                                                 break;
4264                                         }
4265                                         x.bv_val += is->bv_len + 1;
4266                                         x.bv_len -= is->bv_len + 1;
4267
4268                                         /* eat leading spaces */
4269                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4270                                                 /* empty */;
4271                                         }
4272
4273                                         if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4274                                         x.bv_val++;
4275                                         x.bv_len--;
4276
4277                                         have2 |= HAVE_ISSUER;
4278
4279                                 } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) {
4280                                         if ( have2 & HAVE_SN ) {
4281                                                 return LDAP_INVALID_SYNTAX;
4282                                         }
4283
4284                                         x.bv_val += STRLENOF("serial ");
4285                                         x.bv_len -= STRLENOF("serial ");
4286
4287                                         /* eat leading spaces */
4288                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
4289                                                 /* empty */;
4290                                         }
4291
4292                                         if ( checkNum( &x, i_sn ) ) {
4293                                                 return LDAP_INVALID_SYNTAX;
4294                                         }
4295
4296                                         x.bv_val += i_sn->bv_len;
4297                                         x.bv_len -= i_sn->bv_len;
4298
4299                                         have2 |= HAVE_SN;
4300
4301                                 } else {
4302                                         return LDAP_INVALID_SYNTAX;
4303                                 }
4304
4305                                 /* eat leading spaces */
4306                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4307                                         /* empty */;
4308                                 }
4309
4310                                 if ( have2 == HAVE_ALL ) {
4311                                         break;
4312                                 }
4313
4314                                 if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
4315                                 x.bv_val++;
4316                                 x.bv_len--;
4317                         } while ( 1 );
4318
4319                         if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4320                         x.bv_val++;
4321                         x.bv_len--;
4322
4323                         /* eat leading spaces */
4324                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4325                                 /* empty */;
4326                         }
4327
4328                         if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4329                         x.bv_val++;
4330                         x.bv_len--;
4331
4332                         have |= HAVE_ISSUER;
4333
4334                 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) {
4335                         if ( have & HAVE_SN ) {
4336                                 return LDAP_INVALID_SYNTAX;
4337                         }
4338
4339                         /* parse serialNumber */
4340                         x.bv_val += STRLENOF("serialNumber");
4341                         x.bv_len -= STRLENOF("serialNumber");
4342
4343                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4344                         x.bv_val++;
4345                         x.bv_len--;
4346
4347                         /* eat leading spaces */
4348                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4349                                 /* empty */;
4350                         }
4351                         
4352                         if ( checkNum( &x, sn ) ) {
4353                                 return LDAP_INVALID_SYNTAX;
4354                         }
4355
4356                         x.bv_val += sn->bv_len;
4357                         x.bv_len -= sn->bv_len;
4358
4359                         have |= HAVE_SN;
4360
4361                 } else {
4362                         return LDAP_INVALID_SYNTAX;
4363                 }
4364
4365                 /* eat spaces */
4366                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4367                         /* empty */;
4368                 }
4369
4370                 if ( have == HAVE_ALL ) {
4371                         break;
4372                 }
4373
4374                 if ( x.bv_val[0] != ',' ) {
4375                         return LDAP_INVALID_SYNTAX;
4376                 }
4377                 x.bv_val++ ;
4378                 x.bv_len--;
4379         } while ( 1 );
4380
4381         /* should have no characters left... */
4382         if( x.bv_len ) return LDAP_INVALID_SYNTAX;
4383
4384         if ( numdquotes == 0 ) {
4385                 ber_dupbv_x( &ni, is, ctx );
4386
4387         } else {
4388                 ber_int_t src, dst;
4389                 
4390                 ni.bv_len = is->bv_len - numdquotes;
4391                 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
4392                 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
4393                         if ( is->bv_val[src] == '"' ) {
4394                                 src++;
4395                         }
4396                         ni.bv_val[dst] = is->bv_val[src];
4397                 }
4398                 ni.bv_val[dst] = '\0';
4399         }
4400
4401         *is = ni;
4402
4403         /* need to handle double dquotes here */
4404         return 0;
4405 }
4406
4407 /* X.509 PMI serialNumberAndIssuerSerialValidate */
4408 static int
4409 serialNumberAndIssuerSerialValidate(
4410         Syntax *syntax,
4411         struct berval *in )
4412 {
4413         int rc;
4414         struct berval sn, i, i_sn;
4415
4416         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n",
4417                 in->bv_val, 0, 0 );
4418
4419         rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL );
4420         if ( rc ) {
4421                 goto done;
4422         }
4423
4424         /* validate DN -- doesn't handle double dquote */ 
4425         rc = dnValidate( NULL, &i );
4426         if ( rc ) {
4427                 rc = LDAP_INVALID_SYNTAX;
4428         }
4429
4430         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4431                 slap_sl_free( i.bv_val, NULL );
4432         }
4433
4434 done:;
4435         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n",
4436                 in->bv_val, rc, 0 );
4437
4438         return rc;
4439 }
4440
4441 /* X.509 PMI serialNumberAndIssuerSerialPretty */
4442 static int
4443 serialNumberAndIssuerSerialPretty(
4444         Syntax *syntax,
4445         struct berval *in,
4446         struct berval *out,
4447         void *ctx )
4448 {
4449         struct berval sn, i, i_sn, ni = BER_BVNULL;
4450         char *p;
4451         int rc;
4452
4453         assert( in != NULL );
4454         assert( out != NULL );
4455
4456         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n",
4457                 in->bv_val, 0, 0 );
4458
4459         rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4460         if ( rc ) {
4461                 goto done;
4462         }
4463
4464         rc = dnPretty( syntax, &i, &ni, ctx );
4465
4466         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4467                 slap_sl_free( i.bv_val, ctx );
4468         }
4469
4470         if ( rc ) {
4471                 rc = LDAP_INVALID_SYNTAX;
4472                 goto done;
4473         }
4474
4475         /* make room from sn + "$" */
4476         out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }")
4477                 + sn.bv_len + ni.bv_len + i_sn.bv_len;
4478         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4479
4480         if ( out->bv_val == NULL ) {
4481                 out->bv_len = 0;
4482                 rc = LDAP_OTHER;
4483                 goto done;
4484         }
4485
4486         p = out->bv_val;
4487         p = lutil_strcopy( p, "{ serialNumber " );
4488         p = lutil_strncopy( p, sn.bv_val, sn.bv_len );
4489         p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4490         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
4491         p = lutil_strcopy( p, "\" }, serial " );
4492         p = lutil_strncopy( p, i_sn.bv_val, i_sn.bv_len );
4493         p = lutil_strcopy( p, " } } }" );
4494
4495         assert( p == &out->bv_val[out->bv_len] );
4496
4497 done:;
4498         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n",
4499                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4500
4501         slap_sl_free( ni.bv_val, ctx );
4502
4503         return rc; 
4504 }
4505
4506 /* X.509 PMI serialNumberAndIssuerSerialNormalize */
4507 /*
4508  * This routine is called by attributeCertificateExactNormalize
4509  * when attributeCertificateExactNormalize receives a search 
4510  * string instead of a attribute certificate. This routine 
4511  * checks if the search value is valid and then returns the 
4512  * normalized value
4513  */
4514 static int
4515 serialNumberAndIssuerSerialNormalize(
4516         slap_mask_t usage,
4517         Syntax *syntax,
4518         MatchingRule *mr,
4519         struct berval *in,
4520         struct berval *out,
4521         void *ctx )
4522 {
4523         struct berval i, ni = BER_BVNULL,
4524                 sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL,
4525                 i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL;
4526         char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN],
4527                 sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN];
4528         char *p;
4529         int rc;
4530
4531         assert( in != NULL );
4532         assert( out != NULL );
4533
4534         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n",
4535                 in->bv_val, 0, 0 );
4536
4537         rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4538         if ( rc ) {
4539                 goto func_leave;
4540         }
4541
4542         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4543
4544         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4545                 slap_sl_free( i.bv_val, ctx );
4546         }
4547
4548         if ( rc ) {
4549                 rc = LDAP_INVALID_SYNTAX;
4550                 goto func_leave;
4551         }
4552
4553         /* Convert sn to canonical hex */
4554         sn2.bv_val = sbuf2;
4555         sn2.bv_len = sn.bv_len;
4556         if ( sn.bv_len > sizeof( sbuf2 ) ) {
4557                 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
4558         }
4559         if ( lutil_str2bin( &sn, &sn2, ctx ) ) {
4560                 rc = LDAP_INVALID_SYNTAX;
4561                 goto func_leave;
4562         }
4563
4564         /* Convert i_sn to canonical hex */
4565         i_sn2.bv_val = i_sbuf2;
4566         i_sn2.bv_len = i_sn.bv_len;
4567         if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) {
4568                 i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx );
4569         }
4570         if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) {
4571                 rc = LDAP_INVALID_SYNTAX;
4572                 goto func_leave;
4573         }
4574
4575         sn3.bv_val = sbuf3;
4576         sn3.bv_len = sizeof(sbuf3);
4577         if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
4578                 rc = LDAP_INVALID_SYNTAX;
4579                 goto func_leave;
4580         }
4581
4582         i_sn3.bv_val = i_sbuf3;
4583         i_sn3.bv_len = sizeof(i_sbuf3);
4584         if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) {
4585                 rc = LDAP_INVALID_SYNTAX;
4586                 goto func_leave;
4587         }
4588
4589         out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }")
4590                 + sn3.bv_len + ni.bv_len + i_sn3.bv_len;
4591         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4592
4593         if ( out->bv_val == NULL ) {
4594                 out->bv_len = 0;
4595                 rc = LDAP_OTHER;
4596                 goto func_leave;
4597         }
4598
4599         p = out->bv_val;
4600
4601         p = lutil_strcopy( p, "{ serialNumber " );
4602         p = lutil_strncopy( p, sn3.bv_val, sn3.bv_len );
4603         p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4604         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
4605         p = lutil_strcopy( p, "\" }, serial " );
4606         p = lutil_strncopy( p, i_sn3.bv_val, i_sn3.bv_len );
4607         p = lutil_strcopy( p, " } } }" );
4608
4609         assert( p == &out->bv_val[out->bv_len] );
4610
4611 func_leave:
4612         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n",
4613                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4614
4615         if ( sn2.bv_val != sbuf2 ) {
4616                 slap_sl_free( sn2.bv_val, ctx );
4617         }
4618
4619         if ( i_sn2.bv_val != i_sbuf2 ) {
4620                 slap_sl_free( i_sn2.bv_val, ctx );
4621         }
4622
4623         if ( sn3.bv_val != sbuf3 ) {
4624                 slap_sl_free( sn3.bv_val, ctx );
4625         }
4626
4627         if ( i_sn3.bv_val != i_sbuf3 ) {
4628                 slap_sl_free( i_sn3.bv_val, ctx );
4629         }
4630
4631         slap_sl_free( ni.bv_val, ctx );
4632
4633         return rc;
4634 }
4635
4636 /* X.509 PMI attributeCertificateExactNormalize */
4637 static int
4638 attributeCertificateExactNormalize(
4639         slap_mask_t usage,
4640         Syntax *syntax,
4641         MatchingRule *mr,
4642         struct berval *val,
4643         struct berval *normalized,
4644         void *ctx )
4645 {
4646         BerElementBuffer berbuf;
4647         BerElement *ber = (BerElement *)&berbuf;
4648         ber_tag_t tag;
4649         ber_len_t len;
4650         char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN];
4651         struct berval sn, i_sn, sn2, i_sn2;
4652         struct berval issuer_dn = BER_BVNULL, bvdn;
4653         char *p;
4654         int rc = LDAP_INVALID_SYNTAX;
4655
4656         if ( BER_BVISEMPTY( val ) ) {
4657                 goto done;
4658         }
4659
4660         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4661                 return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx );
4662         }
4663
4664         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4665
4666         ber_init2( ber, val, LBER_USE_DER );
4667         tag = ber_skip_tag( ber, &len );        /* Signed Sequence */
4668         tag = ber_skip_tag( ber, &len );        /* Sequence */
4669         tag = ber_skip_tag( ber, &len );        /* (Mandatory) version; must be v2(1) */
4670         ber_skip_data( ber, len );
4671         tag = ber_skip_tag( ber, &len );        /* Holder Sequence */
4672         ber_skip_data( ber, len );
4673
4674         /* Issuer */
4675         tag = ber_skip_tag( ber, &len );        /* Sequence */
4676                                                 /* issuerName (GeneralNames sequence; optional)? */
4677         tag = ber_skip_tag( ber, &len );        /* baseCertificateID (sequence; optional)? */
4678         tag = ber_skip_tag( ber, &len );        /* GeneralNames (sequence) */
4679         tag = ber_skip_tag( ber, &len );        /* directoryName (we only accept this form of GeneralName) */
4680         if ( tag != SLAP_X509_GN_DIRECTORYNAME ) { 
4681                 rc = LDAP_INVALID_SYNTAX; 
4682                 goto done;
4683         }
4684         tag = ber_peek_tag( ber, &len );        /* sequence of RDN */
4685         len = ber_ptrlen( ber );
4686         bvdn.bv_val = val->bv_val + len;
4687         bvdn.bv_len = val->bv_len - len;
4688         rc = dnX509normalize( &bvdn, &issuer_dn );
4689         if ( rc != LDAP_SUCCESS ) goto done;
4690         
4691         tag = ber_skip_tag( ber, &len );        /* sequence of RDN */
4692         ber_skip_data( ber, len ); 
4693         tag = ber_skip_tag( ber, &len );        /* serial number */
4694         if ( tag != LBER_INTEGER ) {
4695                 rc = LDAP_INVALID_SYNTAX; 
4696                 goto done;
4697         }
4698         i_sn.bv_val = (char *)ber->ber_ptr;
4699         i_sn.bv_len = len;
4700         i_sn2.bv_val = issuer_serialbuf;
4701         i_sn2.bv_len = sizeof(issuer_serialbuf);
4702         if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) {
4703                 rc = LDAP_INVALID_SYNTAX;
4704                 goto done;
4705         }
4706         ber_skip_data( ber, len );
4707
4708                                                 /* issuerUID (bitstring; optional)? */
4709                                                 /* objectDigestInfo (sequence; optional)? */
4710
4711         tag = ber_skip_tag( ber, &len );        /* Signature (sequence) */
4712         ber_skip_data( ber, len );
4713         tag = ber_skip_tag( ber, &len );        /* serial number */ 
4714         if ( tag != LBER_INTEGER ) {
4715                 rc = LDAP_INVALID_SYNTAX; 
4716                 goto done;
4717         }
4718         sn.bv_val = (char *)ber->ber_ptr;
4719         sn.bv_len = len;
4720         sn2.bv_val = serialbuf;
4721         sn2.bv_len = sizeof(serialbuf);
4722         if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
4723                 rc = LDAP_INVALID_SYNTAX;
4724                 goto done;
4725         }
4726         ber_skip_data( ber, len );
4727
4728         normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }" )
4729                 + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len;
4730         normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4731
4732         p = normalized->bv_val;
4733
4734         p = lutil_strcopy( p, "{ serialNumber " );
4735         p = lutil_strncopy( p, sn2.bv_val, sn2.bv_len );
4736         p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4737         p = lutil_strncopy( p, issuer_dn.bv_val, issuer_dn.bv_len );
4738         p = lutil_strcopy( p, "\" }, serial " );
4739         p = lutil_strncopy( p, i_sn2.bv_val, i_sn2.bv_len );
4740         p = lutil_strcopy( p, " } } }" );
4741
4742         Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n",
4743                 normalized->bv_val, NULL, NULL );
4744
4745         rc = LDAP_SUCCESS;
4746
4747 done:
4748         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4749         if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx );
4750         if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx );
4751
4752         return rc;
4753 }
4754
4755
4756 static int
4757 hexValidate(
4758         Syntax *syntax,
4759         struct berval *in )
4760 {
4761         ber_len_t       i;
4762
4763         assert( in != NULL );
4764         assert( !BER_BVISNULL( in ) );
4765
4766         for ( i = 0; i < in->bv_len; i++ ) {
4767                 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
4768                         return LDAP_INVALID_SYNTAX;
4769                 }
4770         }
4771
4772         return LDAP_SUCCESS;
4773 }
4774
4775 /* Normalize a SID as used inside a CSN:
4776  * three-digit numeric string */
4777 static int
4778 hexNormalize(
4779         slap_mask_t usage,
4780         Syntax *syntax,
4781         MatchingRule *mr,
4782         struct berval *val,
4783         struct berval *normalized,
4784         void *ctx )
4785 {
4786         ber_len_t       i;
4787
4788         assert( val != NULL );
4789         assert( normalized != NULL );
4790
4791         ber_dupbv_x( normalized, val, ctx );
4792
4793         for ( i = 0; i < normalized->bv_len; i++ ) {
4794                 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
4795                         ber_memfree_x( normalized->bv_val, ctx );
4796                         BER_BVZERO( normalized );
4797                         return LDAP_INVALID_SYNTAX;
4798                 }
4799
4800                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
4801         }
4802
4803         return LDAP_SUCCESS;
4804 }
4805
4806 static int
4807 sidValidate (
4808         Syntax *syntax,
4809         struct berval *in )
4810 {
4811         assert( in != NULL );
4812         assert( !BER_BVISNULL( in ) );
4813
4814         if ( in->bv_len != 3 ) {
4815                 return LDAP_INVALID_SYNTAX;
4816         }
4817
4818         return hexValidate( NULL, in );
4819 }
4820
4821 /* Normalize a SID as used inside a CSN:
4822  * three-digit numeric string */
4823 static int
4824 sidNormalize(
4825         slap_mask_t usage,
4826         Syntax *syntax,
4827         MatchingRule *mr,
4828         struct berval *val,
4829         struct berval *normalized,
4830         void *ctx )
4831 {
4832         if ( val->bv_len != 3 ) {
4833                 return LDAP_INVALID_SYNTAX;
4834         }
4835
4836         return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
4837 }
4838
4839 static int
4840 sidPretty(
4841         Syntax *syntax,
4842         struct berval *val,
4843         struct berval *out,
4844         void *ctx )
4845 {
4846         return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
4847 }
4848
4849 /* Normalize a SID as used inside a CSN, either as-is
4850  * (assertion value) or extracted from the CSN
4851  * (attribute value) */
4852 static int
4853 csnSidNormalize(
4854         slap_mask_t usage,
4855         Syntax *syntax,
4856         MatchingRule *mr,
4857         struct berval *val,
4858         struct berval *normalized,
4859         void *ctx )
4860 {
4861         struct berval   bv;
4862         char            *ptr,
4863                         buf[ 4 ];
4864
4865
4866         if ( BER_BVISEMPTY( val ) ) {
4867                 return LDAP_INVALID_SYNTAX;
4868         }
4869
4870         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4871                 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
4872         }
4873
4874         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4875
4876         ptr = ber_bvchr( val, '#' );
4877         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4878                 return LDAP_INVALID_SYNTAX;
4879         }
4880
4881         bv.bv_val = ptr + 1;
4882         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
4883
4884         ptr = ber_bvchr( &bv, '#' );
4885         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4886                 return LDAP_INVALID_SYNTAX;
4887         }
4888
4889         bv.bv_val = ptr + 1;
4890         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
4891                 
4892         ptr = ber_bvchr( &bv, '#' );
4893         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4894                 return LDAP_INVALID_SYNTAX;
4895         }
4896
4897         bv.bv_len = ptr - bv.bv_val;
4898
4899         if ( bv.bv_len == 2 ) {
4900                 /* OpenLDAP 2.3 SID */
4901                 buf[ 0 ] = '0';
4902                 buf[ 1 ] = bv.bv_val[ 0 ];
4903                 buf[ 2 ] = bv.bv_val[ 1 ];
4904                 buf[ 3 ] = '\0';
4905
4906                 bv.bv_val = buf;
4907                 bv.bv_len = 3;
4908         }
4909
4910         return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
4911 }
4912
4913 static int
4914 csnValidate(
4915         Syntax *syntax,
4916         struct berval *in )
4917 {
4918         struct berval   bv;
4919         char            *ptr;
4920         int             rc;
4921
4922         assert( in != NULL );
4923         assert( !BER_BVISNULL( in ) );
4924
4925         if ( BER_BVISEMPTY( in ) ) {
4926                 return LDAP_INVALID_SYNTAX;
4927         }
4928
4929         bv = *in;
4930
4931         ptr = ber_bvchr( &bv, '#' );
4932         if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) {
4933                 return LDAP_INVALID_SYNTAX;
4934         }
4935
4936         bv.bv_len = ptr - bv.bv_val;
4937         if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
4938                 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
4939         {
4940                 return LDAP_INVALID_SYNTAX;
4941         }
4942
4943         rc = generalizedTimeValidate( NULL, &bv );
4944         if ( rc != LDAP_SUCCESS ) {
4945                 return rc;
4946         }
4947
4948         bv.bv_val = ptr + 1;
4949         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
4950
4951         ptr = ber_bvchr( &bv, '#' );
4952         if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
4953                 return LDAP_INVALID_SYNTAX;
4954         }
4955
4956         bv.bv_len = ptr - bv.bv_val;
4957         if ( bv.bv_len != 6 ) {
4958                 return LDAP_INVALID_SYNTAX;
4959         }
4960
4961         rc = hexValidate( NULL, &bv );
4962         if ( rc != LDAP_SUCCESS ) {
4963                 return rc;
4964         }
4965
4966         bv.bv_val = ptr + 1;
4967         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
4968
4969         ptr = ber_bvchr( &bv, '#' );
4970         if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
4971                 return LDAP_INVALID_SYNTAX;
4972         }
4973
4974         bv.bv_len = ptr - bv.bv_val;
4975         if ( bv.bv_len == 2 ) {
4976                 /* tolerate old 2-digit replica-id */
4977                 rc = hexValidate( NULL, &bv );
4978
4979         } else {
4980                 rc = sidValidate( NULL, &bv );
4981         }
4982         if ( rc != LDAP_SUCCESS ) {
4983                 return rc;
4984         }
4985
4986         bv.bv_val = ptr + 1;
4987         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
4988
4989         if ( bv.bv_len != 6 ) {
4990                 return LDAP_INVALID_SYNTAX;
4991         }
4992
4993         return hexValidate( NULL, &bv );
4994 }
4995
4996 /* Normalize a CSN in OpenLDAP 2.1 format */
4997 static int
4998 csnNormalize21(
4999         slap_mask_t usage,
5000         Syntax *syntax,
5001         MatchingRule *mr,
5002         struct berval *val,
5003         struct berval *normalized,
5004         void *ctx )
5005 {
5006         struct berval   gt, cnt, sid, mod;
5007         struct berval   bv;
5008         char            buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5009         char            *ptr;
5010         ber_len_t       i;
5011
5012         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5013         assert( !BER_BVISEMPTY( val ) );
5014
5015         gt = *val;
5016
5017         ptr = ber_bvchr( &gt, '#' );
5018         if ( ptr == NULL || ptr == &gt.bv_val[gt.bv_len] ) {
5019                 return LDAP_INVALID_SYNTAX;
5020         }
5021
5022         gt.bv_len = ptr - gt.bv_val;
5023         if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
5024                 return LDAP_INVALID_SYNTAX;
5025         }
5026
5027         if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
5028                 return LDAP_INVALID_SYNTAX;
5029         }
5030
5031         cnt.bv_val = ptr + 1;
5032         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5033
5034         ptr = ber_bvchr( &cnt, '#' );
5035         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5036                 return LDAP_INVALID_SYNTAX;
5037         }
5038
5039         cnt.bv_len = ptr - cnt.bv_val;
5040         if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
5041                 return LDAP_INVALID_SYNTAX;
5042         }
5043
5044         if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
5045                 return LDAP_INVALID_SYNTAX;
5046         }
5047
5048         cnt.bv_val += STRLENOF( "0x" );
5049         cnt.bv_len -= STRLENOF( "0x" );
5050
5051         sid.bv_val = ptr + 1;
5052         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5053                 
5054         ptr = ber_bvchr( &sid, '#' );
5055         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5056                 return LDAP_INVALID_SYNTAX;
5057         }
5058
5059         sid.bv_len = ptr - sid.bv_val;
5060         if ( sid.bv_len != STRLENOF( "0" ) ) {
5061                 return LDAP_INVALID_SYNTAX;
5062         }
5063
5064         mod.bv_val = ptr + 1;
5065         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5066         if ( mod.bv_len != STRLENOF( "0000" ) ) {
5067                 return LDAP_INVALID_SYNTAX;
5068         }
5069
5070         bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5071         bv.bv_val = buf;
5072
5073         ptr = bv.bv_val;
5074         ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
5075         ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
5076                 STRLENOF( "MM" ) );
5077         ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
5078                 STRLENOF( "SS" ) );
5079         ptr = lutil_strcopy( ptr, ".000000Z#00" );
5080         ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
5081         *ptr++ = '#';
5082         *ptr++ = '0';
5083         *ptr++ = '0';
5084         *ptr++ = sid.bv_val[ 0 ];
5085         *ptr++ = '#';
5086         *ptr++ = '0';
5087         *ptr++ = '0';
5088         for ( i = 0; i < mod.bv_len; i++ ) {
5089                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5090         }
5091         *ptr = '\0';
5092
5093         assert( ptr == &bv.bv_val[bv.bv_len] );
5094
5095         if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5096                 return LDAP_INVALID_SYNTAX;
5097         }
5098
5099         ber_dupbv_x( normalized, &bv, ctx );
5100
5101         return LDAP_SUCCESS;
5102 }
5103
5104 /* Normalize a CSN in OpenLDAP 2.3 format */
5105 static int
5106 csnNormalize23(
5107         slap_mask_t usage,
5108         Syntax *syntax,
5109         MatchingRule *mr,
5110         struct berval *val,
5111         struct berval *normalized,
5112         void *ctx )
5113 {
5114         struct berval   gt, cnt, sid, mod;
5115         struct berval   bv;
5116         char            buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5117         char            *ptr;
5118         ber_len_t       i;
5119
5120         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5121         assert( !BER_BVISEMPTY( val ) );
5122
5123         gt = *val;
5124
5125         ptr = ber_bvchr( &gt, '#' );
5126         if ( ptr == NULL || ptr == &gt.bv_val[gt.bv_len] ) {
5127                 return LDAP_INVALID_SYNTAX;
5128         }
5129
5130         gt.bv_len = ptr - gt.bv_val;
5131         if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
5132                 return LDAP_INVALID_SYNTAX;
5133         }
5134
5135         cnt.bv_val = ptr + 1;
5136         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5137
5138         ptr = ber_bvchr( &cnt, '#' );
5139         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5140                 return LDAP_INVALID_SYNTAX;
5141         }
5142
5143         cnt.bv_len = ptr - cnt.bv_val;
5144         if ( cnt.bv_len != STRLENOF( "000000" ) ) {
5145                 return LDAP_INVALID_SYNTAX;
5146         }
5147
5148         sid.bv_val = ptr + 1;
5149         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5150                 
5151         ptr = ber_bvchr( &sid, '#' );
5152         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5153                 return LDAP_INVALID_SYNTAX;
5154         }
5155
5156         sid.bv_len = ptr - sid.bv_val;
5157         if ( sid.bv_len != STRLENOF( "00" ) ) {
5158                 return LDAP_INVALID_SYNTAX;
5159         }
5160
5161         mod.bv_val = ptr + 1;
5162         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5163         if ( mod.bv_len != STRLENOF( "000000" ) ) {
5164                 return LDAP_INVALID_SYNTAX;
5165         }
5166
5167         bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5168         bv.bv_val = buf;
5169
5170         ptr = bv.bv_val;
5171         ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
5172         ptr = lutil_strcopy( ptr, ".000000Z#" );
5173         ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
5174         *ptr++ = '#';
5175         *ptr++ = '0';
5176         for ( i = 0; i < sid.bv_len; i++ ) {
5177                 *ptr++ = TOLOWER( sid.bv_val[ i ] );
5178         }
5179         *ptr++ = '#';
5180         for ( i = 0; i < mod.bv_len; i++ ) {
5181                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5182         }
5183         *ptr = '\0';
5184
5185         assert( ptr == &bv.bv_val[bv.bv_len] );
5186         if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5187                 return LDAP_INVALID_SYNTAX;
5188         }
5189
5190         ber_dupbv_x( normalized, &bv, ctx );
5191
5192         return LDAP_SUCCESS;
5193 }
5194
5195 /* Normalize a CSN */
5196 static int
5197 csnNormalize(
5198         slap_mask_t usage,
5199         Syntax *syntax,
5200         MatchingRule *mr,
5201         struct berval *val,
5202         struct berval *normalized,
5203         void *ctx )
5204 {
5205         struct berval   cnt, sid, mod;
5206         char            *ptr;
5207         ber_len_t       i;
5208
5209         assert( val != NULL );
5210         assert( normalized != NULL );
5211
5212         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5213
5214         if ( BER_BVISEMPTY( val ) ) {
5215                 return LDAP_INVALID_SYNTAX;
5216         }
5217
5218         if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
5219                 /* Openldap <= 2.3 */
5220
5221                 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
5222         }
5223
5224         if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
5225                 /* Openldap 2.1 */
5226
5227                 return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
5228         }
5229
5230         if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
5231                 return LDAP_INVALID_SYNTAX;
5232         }
5233
5234         ptr = ber_bvchr( val, '#' );
5235         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5236                 return LDAP_INVALID_SYNTAX;
5237         }
5238
5239         if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
5240                 return LDAP_INVALID_SYNTAX;
5241         }
5242
5243         cnt.bv_val = ptr + 1;
5244         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5245
5246         ptr = ber_bvchr( &cnt, '#' );
5247         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5248                 return LDAP_INVALID_SYNTAX;
5249         }
5250
5251         if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
5252                 return LDAP_INVALID_SYNTAX;
5253         }
5254
5255         sid.bv_val = ptr + 1;
5256         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5257                 
5258         ptr = ber_bvchr( &sid, '#' );
5259         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5260                 return LDAP_INVALID_SYNTAX;
5261         }
5262
5263         sid.bv_len = ptr - sid.bv_val;
5264         if ( sid.bv_len != STRLENOF( "000" ) ) {
5265                 return LDAP_INVALID_SYNTAX;
5266         }
5267
5268         mod.bv_val = ptr + 1;
5269         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5270
5271         if ( mod.bv_len != STRLENOF( "000000" ) ) {
5272                 return LDAP_INVALID_SYNTAX;
5273         }
5274
5275         ber_dupbv_x( normalized, val, ctx );
5276
5277         for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
5278                 i < normalized->bv_len; i++ )
5279         {
5280                 /* assume it's already validated that's all hex digits */
5281                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5282         }
5283
5284         return LDAP_SUCCESS;
5285 }
5286
5287 static int
5288 csnPretty(
5289         Syntax *syntax,
5290         struct berval *val,
5291         struct berval *out,
5292         void *ctx )
5293 {
5294         return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5295 }
5296
5297 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
5298 /* slight optimization - does not need the start parameter */
5299 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
5300 enum { start = 0 };
5301 #endif
5302
5303 static int
5304 check_time_syntax (struct berval *val,
5305         int start,
5306         int *parts,
5307         struct berval *fraction)
5308 {
5309         /*
5310          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
5311          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
5312          * GeneralizedTime supports leap seconds, UTCTime does not.
5313          */
5314         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
5315         static const int mdays[2][12] = {
5316                 /* non-leap years */
5317                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
5318                 /* leap years */
5319                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
5320         };
5321         char *p, *e;
5322         int part, c, c1, c2, tzoffset, leapyear = 0;
5323
5324         p = val->bv_val;
5325         e = p + val->bv_len;
5326
5327 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5328         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
5329 #endif
5330         for (part = start; part < 7 && p < e; part++) {
5331                 c1 = *p;
5332                 if (!ASCII_DIGIT(c1)) {
5333                         break;
5334                 }
5335                 p++;
5336                 if (p == e) {
5337                         return LDAP_INVALID_SYNTAX;
5338                 }
5339                 c = *p++;
5340                 if (!ASCII_DIGIT(c)) {
5341                         return LDAP_INVALID_SYNTAX;
5342                 }
5343                 c += c1 * 10 - '0' * 11;
5344                 if ((part | 1) == 3) {
5345                         --c;
5346                         if (c < 0) {
5347                                 return LDAP_INVALID_SYNTAX;
5348                         }
5349                 }
5350                 if (c >= ceiling[part]) {
5351                         if (! (c == 60 && part == 6 && start == 0))
5352                                 return LDAP_INVALID_SYNTAX;
5353                 }
5354                 parts[part] = c;
5355         }
5356         if (part < 5 + start) {
5357                 return LDAP_INVALID_SYNTAX;
5358         }
5359         for (; part < 9; part++) {
5360                 parts[part] = 0;
5361         }
5362
5363         /* leapyear check for the Gregorian calendar (year>1581) */
5364         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
5365                 leapyear = 1;
5366         }
5367
5368         if (parts[3] >= mdays[leapyear][parts[2]]) {
5369                 return LDAP_INVALID_SYNTAX;
5370         }
5371
5372         if (start == 0) {
5373                 fraction->bv_val = p;
5374                 fraction->bv_len = 0;
5375                 if (p < e && (*p == '.' || *p == ',')) {
5376                         char *end_num;
5377                         while (++p < e && ASCII_DIGIT(*p)) {
5378                                 /* EMTPY */;
5379                         }
5380                         if (p - fraction->bv_val == 1) {
5381                                 return LDAP_INVALID_SYNTAX;
5382                         }
5383                         for (end_num = p; end_num[-1] == '0'; --end_num) {
5384                                 /* EMPTY */;
5385                         }
5386                         c = end_num - fraction->bv_val;
5387                         if (c != 1) fraction->bv_len = c;
5388                 }
5389         }
5390
5391         if (p == e) {
5392                 /* no time zone */
5393                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5394         }
5395
5396         tzoffset = *p++;
5397         switch (tzoffset) {
5398         default:
5399                 return LDAP_INVALID_SYNTAX;
5400         case 'Z':
5401                 /* UTC */
5402                 break;
5403         case '+':
5404         case '-':
5405                 for (part = 7; part < 9 && p < e; part++) {
5406                         c1 = *p;
5407                         if (!ASCII_DIGIT(c1)) {
5408                                 break;
5409                         }
5410                         p++;
5411                         if (p == e) {
5412                                 return LDAP_INVALID_SYNTAX;
5413                         }
5414                         c2 = *p++;
5415                         if (!ASCII_DIGIT(c2)) {
5416                                 return LDAP_INVALID_SYNTAX;
5417                         }
5418                         parts[part] = c1 * 10 + c2 - '0' * 11;
5419                         if (parts[part] >= ceiling[part]) {
5420                                 return LDAP_INVALID_SYNTAX;
5421                         }
5422                 }
5423                 if (part < 8 + start) {
5424                         return LDAP_INVALID_SYNTAX;
5425                 }
5426
5427                 if (tzoffset == '-') {
5428                         /* negative offset to UTC, ie west of Greenwich */
5429                         parts[4] += parts[7];
5430                         parts[5] += parts[8];
5431                         /* offset is just hhmm, no seconds */
5432                         for (part = 6; --part >= 0; ) {
5433                                 if (part != 3) {
5434                                         c = ceiling[part];
5435                                 } else {
5436                                         c = mdays[leapyear][parts[2]];
5437                                 }
5438                                 if (parts[part] >= c) {
5439                                         if (part == 0) {
5440                                                 return LDAP_INVALID_SYNTAX;
5441                                         }
5442                                         parts[part] -= c;
5443                                         parts[part - 1]++;
5444                                         continue;
5445                                 } else if (part != 5) {
5446                                         break;
5447                                 }
5448                         }
5449                 } else {
5450                         /* positive offset to UTC, ie east of Greenwich */
5451                         parts[4] -= parts[7];
5452                         parts[5] -= parts[8];
5453                         for (part = 6; --part >= 0; ) {
5454                                 if (parts[part] < 0) {
5455                                         if (part == 0) {
5456                                                 return LDAP_INVALID_SYNTAX;
5457                                         }
5458                                         if (part != 3) {
5459                                                 c = ceiling[part];
5460                                         } else {
5461                                                 /* make first arg to % non-negative */
5462                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
5463                                         }
5464                                         parts[part] += c;
5465                                         parts[part - 1]--;
5466                                         continue;
5467                                 } else if (part != 5) {
5468                                         break;
5469                                 }
5470                         }
5471                 }
5472         }
5473
5474         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5475 }
5476
5477 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5478
5479 #if 0
5480 static int
5481 xutcTimeNormalize(
5482         Syntax *syntax,
5483         struct berval *val,
5484         struct berval *normalized )
5485 {
5486         int parts[9], rc;
5487
5488         rc = check_time_syntax(val, 1, parts, NULL);
5489         if (rc != LDAP_SUCCESS) {
5490                 return rc;
5491         }
5492
5493         normalized->bv_val = ch_malloc( 14 );
5494         if ( normalized->bv_val == NULL ) {
5495                 return LBER_ERROR_MEMORY;
5496         }
5497
5498         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
5499                 parts[1], parts[2] + 1, parts[3] + 1,
5500                 parts[4], parts[5], parts[6] );
5501         normalized->bv_len = 13;
5502
5503         return LDAP_SUCCESS;
5504 }
5505 #endif /* 0 */
5506
5507 static int
5508 utcTimeValidate(
5509         Syntax *syntax,
5510         struct berval *in )
5511 {
5512         int parts[9];
5513         return check_time_syntax(in, 1, parts, NULL);
5514 }
5515
5516 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
5517
5518 static int
5519 generalizedTimeValidate(
5520         Syntax *syntax,
5521         struct berval *in )
5522 {
5523         int parts[9];
5524         struct berval fraction;
5525         return check_time_syntax(in, 0, parts, &fraction);
5526 }
5527
5528 static int
5529 generalizedTimeNormalize(
5530         slap_mask_t usage,
5531         Syntax *syntax,
5532         MatchingRule *mr,
5533         struct berval *val,
5534         struct berval *normalized,
5535         void *ctx )
5536 {
5537         int parts[9], rc;
5538         unsigned int len;
5539         struct berval fraction;
5540
5541         rc = check_time_syntax(val, 0, parts, &fraction);
5542         if (rc != LDAP_SUCCESS) {
5543                 return rc;
5544         }
5545
5546         len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
5547         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
5548         if ( BER_BVISNULL( normalized ) ) {
5549                 return LBER_ERROR_MEMORY;
5550         }
5551
5552         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
5553                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
5554                 parts[4], parts[5], parts[6] );
5555         if ( !BER_BVISEMPTY( &fraction ) ) {
5556                 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
5557                         fraction.bv_val, fraction.bv_len );
5558                 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
5559         }
5560         strcpy( normalized->bv_val + len-1, "Z" );
5561         normalized->bv_len = len;
5562
5563         return LDAP_SUCCESS;
5564 }
5565
5566 static int
5567 generalizedTimeOrderingMatch(
5568         int *matchp,
5569         slap_mask_t flags,
5570         Syntax *syntax,
5571         MatchingRule *mr,
5572         struct berval *value,
5573         void *assertedValue )
5574 {
5575         struct berval *asserted = (struct berval *) assertedValue;
5576         ber_len_t v_len  = value->bv_len;
5577         ber_len_t av_len = asserted->bv_len;
5578
5579         /* ignore trailing 'Z' when comparing */
5580         int match = memcmp( value->bv_val, asserted->bv_val,
5581                 (v_len < av_len ? v_len : av_len) - 1 );
5582         if ( match == 0 ) match = v_len - av_len;
5583
5584         *matchp = match;
5585         return LDAP_SUCCESS;
5586 }
5587
5588 /* Index generation function */
5589 int generalizedTimeIndexer(
5590         slap_mask_t use,
5591         slap_mask_t flags,
5592         Syntax *syntax,
5593         MatchingRule *mr,
5594         struct berval *prefix,
5595         BerVarray values,
5596         BerVarray *keysp,
5597         void *ctx )
5598 {
5599         int i, j;
5600         BerVarray keys;
5601         char tmp[5];
5602         BerValue bvtmp; /* 40 bit index */
5603         struct lutil_tm tm;
5604         struct lutil_timet tt;
5605
5606         bvtmp.bv_len = sizeof(tmp);
5607         bvtmp.bv_val = tmp;
5608         for( i=0; values[i].bv_val != NULL; i++ ) {
5609                 /* just count them */
5610         }
5611
5612         /* we should have at least one value at this point */
5613         assert( i > 0 );
5614
5615         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
5616
5617         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5618         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
5619                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
5620                 /* Use 40 bits of time for key */
5621                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
5622                         lutil_tm2time( &tm, &tt );
5623                         tmp[0] = tt.tt_gsec & 0xff;
5624                         tmp[4] = tt.tt_sec & 0xff;
5625                         tt.tt_sec >>= 8;
5626                         tmp[3] = tt.tt_sec & 0xff;
5627                         tt.tt_sec >>= 8;
5628                         tmp[2] = tt.tt_sec & 0xff;
5629                         tt.tt_sec >>= 8;
5630                         tmp[1] = tt.tt_sec & 0xff;
5631                         
5632                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
5633                 }
5634         }
5635
5636         keys[j].bv_val = NULL;
5637         keys[j].bv_len = 0;
5638
5639         *keysp = keys;
5640
5641         return LDAP_SUCCESS;
5642 }
5643
5644 /* Index generation function */
5645 int generalizedTimeFilter(
5646         slap_mask_t use,
5647         slap_mask_t flags,
5648         Syntax *syntax,
5649         MatchingRule *mr,
5650         struct berval *prefix,
5651         void * assertedValue,
5652         BerVarray *keysp,
5653         void *ctx )
5654 {
5655         BerVarray keys;
5656         char tmp[5];
5657         BerValue bvtmp; /* 40 bit index */
5658         BerValue *value = (BerValue *) assertedValue;
5659         struct lutil_tm tm;
5660         struct lutil_timet tt;
5661         
5662         bvtmp.bv_len = sizeof(tmp);
5663         bvtmp.bv_val = tmp;
5664         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5665         /* Use 40 bits of time for key */
5666         if ( value->bv_val && value->bv_len >= 10 &&
5667                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
5668
5669                 lutil_tm2time( &tm, &tt );
5670                 tmp[0] = tt.tt_gsec & 0xff;
5671                 tmp[4] = tt.tt_sec & 0xff;
5672                 tt.tt_sec >>= 8;
5673                 tmp[3] = tt.tt_sec & 0xff;
5674                 tt.tt_sec >>= 8;
5675                 tmp[2] = tt.tt_sec & 0xff;
5676                 tt.tt_sec >>= 8;
5677                 tmp[1] = tt.tt_sec & 0xff;
5678
5679                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
5680                 ber_dupbv_x(keys, &bvtmp, ctx );
5681                 keys[1].bv_val = NULL;
5682                 keys[1].bv_len = 0;
5683         } else {
5684                 keys = NULL;
5685         }
5686
5687         *keysp = keys;
5688
5689         return LDAP_SUCCESS;
5690 }
5691
5692 static int
5693 deliveryMethodValidate(
5694         Syntax *syntax,
5695         struct berval *val )
5696 {
5697 #undef LENOF
5698 #define LENOF(s) (sizeof(s)-1)
5699         struct berval tmp = *val;
5700         /*
5701      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
5702          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
5703          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
5704          */
5705 again:
5706         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5707
5708         switch( tmp.bv_val[0] ) {
5709         case 'a':
5710         case 'A':
5711                 if(( tmp.bv_len >= LENOF("any") ) &&
5712                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
5713                 {
5714                         tmp.bv_len -= LENOF("any");
5715                         tmp.bv_val += LENOF("any");
5716                         break;
5717                 }
5718                 return LDAP_INVALID_SYNTAX;
5719
5720         case 'm':
5721         case 'M':
5722                 if(( tmp.bv_len >= LENOF("mhs") ) &&
5723                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
5724                 {
5725                         tmp.bv_len -= LENOF("mhs");
5726                         tmp.bv_val += LENOF("mhs");
5727                         break;
5728                 }
5729                 return LDAP_INVALID_SYNTAX;
5730
5731         case 'p':
5732         case 'P':
5733                 if(( tmp.bv_len >= LENOF("physical") ) &&
5734                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
5735                 {
5736                         tmp.bv_len -= LENOF("physical");
5737                         tmp.bv_val += LENOF("physical");
5738                         break;
5739                 }
5740                 return LDAP_INVALID_SYNTAX;
5741
5742         case 't':
5743         case 'T': /* telex or teletex or telephone */
5744                 if(( tmp.bv_len >= LENOF("telex") ) &&
5745                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
5746                 {
5747                         tmp.bv_len -= LENOF("telex");
5748                         tmp.bv_val += LENOF("telex");
5749                         break;
5750                 }
5751                 if(( tmp.bv_len >= LENOF("teletex") ) &&
5752                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
5753                 {
5754                         tmp.bv_len -= LENOF("teletex");
5755                         tmp.bv_val += LENOF("teletex");
5756                         break;
5757                 }
5758                 if(( tmp.bv_len >= LENOF("telephone") ) &&
5759                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
5760                 {
5761                         tmp.bv_len -= LENOF("telephone");
5762                         tmp.bv_val += LENOF("telephone");
5763                         break;
5764                 }
5765                 return LDAP_INVALID_SYNTAX;
5766
5767         case 'g':
5768         case 'G': /* g3fax or g4fax */
5769                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
5770                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
5771                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
5772                 {
5773                         tmp.bv_len -= LENOF("g3fax");
5774                         tmp.bv_val += LENOF("g3fax");
5775                         break;
5776                 }
5777                 return LDAP_INVALID_SYNTAX;
5778
5779         case 'i':
5780         case 'I':
5781                 if(( tmp.bv_len >= LENOF("ia5") ) &&
5782                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
5783                 {
5784                         tmp.bv_len -= LENOF("ia5");
5785                         tmp.bv_val += LENOF("ia5");
5786                         break;
5787                 }
5788                 return LDAP_INVALID_SYNTAX;
5789
5790         case 'v':
5791         case 'V':
5792                 if(( tmp.bv_len >= LENOF("videotex") ) &&
5793                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
5794                 {
5795                         tmp.bv_len -= LENOF("videotex");
5796                         tmp.bv_val += LENOF("videotex");
5797                         break;
5798                 }
5799                 return LDAP_INVALID_SYNTAX;
5800
5801         default:
5802                 return LDAP_INVALID_SYNTAX;
5803         }
5804
5805         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
5806
5807         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5808                 tmp.bv_len++;
5809                 tmp.bv_val--;
5810         }
5811         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
5812                 tmp.bv_len++;
5813                 tmp.bv_val--;
5814         } else {
5815                 return LDAP_INVALID_SYNTAX;
5816         }
5817         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5818                 tmp.bv_len++;
5819                 tmp.bv_val--;
5820         }
5821
5822         goto again;
5823 }
5824
5825 static int
5826 nisNetgroupTripleValidate(
5827         Syntax *syntax,
5828         struct berval *val )
5829 {
5830         char *p, *e;
5831         int commas = 0;
5832
5833         if ( BER_BVISEMPTY( val ) ) {
5834                 return LDAP_INVALID_SYNTAX;
5835         }
5836
5837         p = (char *)val->bv_val;
5838         e = p + val->bv_len;
5839
5840         if ( *p != '(' /*')'*/ ) {
5841                 return LDAP_INVALID_SYNTAX;
5842         }
5843
5844         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
5845                 if ( *p == ',' ) {
5846                         commas++;
5847                         if ( commas > 2 ) {
5848                                 return LDAP_INVALID_SYNTAX;
5849                         }
5850
5851                 } else if ( !AD_CHAR( *p ) ) {
5852                         return LDAP_INVALID_SYNTAX;
5853                 }
5854         }
5855
5856         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
5857                 return LDAP_INVALID_SYNTAX;
5858         }
5859
5860         p++;
5861
5862         if (p != e) {
5863                 return LDAP_INVALID_SYNTAX;
5864         }
5865
5866         return LDAP_SUCCESS;
5867 }
5868
5869 static int
5870 bootParameterValidate(
5871         Syntax *syntax,
5872         struct berval *val )
5873 {
5874         char *p, *e;
5875
5876         if ( BER_BVISEMPTY( val ) ) {
5877                 return LDAP_INVALID_SYNTAX;
5878         }
5879
5880         p = (char *)val->bv_val;
5881         e = p + val->bv_len;
5882
5883         /* key */
5884         for (; ( p < e ) && ( *p != '=' ); p++ ) {
5885                 if ( !AD_CHAR( *p ) ) {
5886                         return LDAP_INVALID_SYNTAX;
5887                 }
5888         }
5889
5890         if ( *p != '=' ) {
5891                 return LDAP_INVALID_SYNTAX;
5892         }
5893
5894         /* server */
5895         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
5896                 if ( !AD_CHAR( *p ) ) {
5897                         return LDAP_INVALID_SYNTAX;
5898                 }
5899         }
5900
5901         if ( *p != ':' ) {
5902                 return LDAP_INVALID_SYNTAX;
5903         }
5904
5905         /* path */
5906         for ( p++; p < e; p++ ) {
5907                 if ( !SLAP_PRINTABLE( *p ) ) {
5908                         return LDAP_INVALID_SYNTAX;
5909                 }
5910         }
5911
5912         return LDAP_SUCCESS;
5913 }
5914
5915 static int
5916 firstComponentNormalize(
5917         slap_mask_t usage,
5918         Syntax *syntax,
5919         MatchingRule *mr,
5920         struct berval *val,
5921         struct berval *normalized,
5922         void *ctx )
5923 {
5924         int rc;
5925         struct berval comp;
5926         ber_len_t len;
5927
5928         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
5929                 ber_dupbv_x( normalized, val, ctx );
5930                 return LDAP_SUCCESS;
5931         }
5932
5933         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5934
5935         if( ! ( val->bv_val[0] == '(' /*')'*/
5936                         && val->bv_val[val->bv_len - 1] == /*'('*/ ')' )
5937                 && ! ( val->bv_val[0] == '{' /*'}'*/
5938                         && val->bv_val[val->bv_len - 1] == /*'('*/ '}' ) )
5939         {
5940                 return LDAP_INVALID_SYNTAX;
5941         }
5942
5943         /* trim leading white space */
5944         for( len=1;
5945                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
5946                 len++ )
5947         {
5948                 /* empty */
5949         }
5950
5951         /* grab next word */
5952         comp.bv_val = &val->bv_val[len];
5953         len = val->bv_len - len - STRLENOF(/*"{"*/ "}");
5954         for( comp.bv_len = 0;
5955                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
5956                 comp.bv_len++ )
5957         {
5958                 /* empty */
5959         }
5960
5961         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
5962                 rc = numericoidValidate( NULL, &comp );
5963         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
5964                 rc = integerValidate( NULL, &comp );
5965         } else {
5966                 rc = LDAP_INVALID_SYNTAX;
5967         }
5968         
5969
5970         if( rc == LDAP_SUCCESS ) {
5971                 ber_dupbv_x( normalized, &comp, ctx );
5972         }
5973
5974         return rc;
5975 }
5976
5977 static char *country_gen_syn[] = {
5978         "1.3.6.1.4.1.1466.115.121.1.15",
5979         "1.3.6.1.4.1.1466.115.121.1.26",
5980         "1.3.6.1.4.1.1466.115.121.1.44",
5981         NULL
5982 };
5983
5984 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
5985 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
5986
5987 static slap_syntax_defs_rec syntax_defs[] = {
5988         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
5989                 X_BINARY X_NOT_H_R ")",
5990                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
5991         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
5992                 0, NULL, NULL, NULL},
5993         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
5994                 0, NULL, NULL, NULL},
5995         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
5996                 X_NOT_H_R ")",
5997                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
5998         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
5999                 X_NOT_H_R ")",
6000                 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6001         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
6002                 0, NULL, bitStringValidate, NULL },
6003         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
6004                 0, NULL, booleanValidate, NULL},
6005         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
6006                 X_BINARY X_NOT_H_R ")",
6007                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6008                 NULL, certificateValidate, NULL},
6009         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
6010                 X_BINARY X_NOT_H_R ")",
6011                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6012                 NULL, certificateListValidate, NULL},
6013         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
6014                 X_BINARY X_NOT_H_R ")",
6015                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6016                 NULL, sequenceValidate, NULL},
6017         {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' "
6018                 X_BINARY X_NOT_H_R ")",
6019                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6020                 NULL, attributeCertificateValidate, NULL},
6021 #if 0   /* need to go __after__ printableString */
6022         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6023                 0, "1.3.6.1.4.1.1466.115.121.1.44",
6024                 countryStringValidate, NULL},
6025 #endif
6026         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
6027                 0, NULL, dnValidate, dnPretty},
6028         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
6029                 0, NULL, rdnValidate, rdnPretty},
6030 #ifdef LDAP_COMP_MATCH
6031         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
6032                 0, NULL, allComponentsValidate, NULL},
6033         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
6034                 0, NULL, componentFilterValidate, NULL},
6035 #endif
6036         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
6037                 0, NULL, NULL, NULL},
6038         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
6039                 0, NULL, deliveryMethodValidate, NULL},
6040         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
6041                 0, NULL, UTF8StringValidate, NULL},
6042         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
6043                 0, NULL, NULL, NULL},
6044         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
6045                 0, NULL, NULL, NULL},
6046         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
6047                 0, NULL, NULL, NULL},
6048         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
6049                 0, NULL, NULL, NULL},
6050         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
6051                 0, NULL, NULL, NULL},
6052         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
6053                 0, NULL, printablesStringValidate, NULL},
6054         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
6055                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
6056         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
6057                 0, NULL, generalizedTimeValidate, NULL},
6058         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
6059                 0, NULL, NULL, NULL},
6060         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
6061                 0, NULL, IA5StringValidate, NULL},
6062         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
6063                 0, NULL, integerValidate, NULL},
6064         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
6065                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6066         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
6067                 0, NULL, NULL, NULL},
6068         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
6069                 0, NULL, NULL, NULL},
6070         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
6071                 0, NULL, NULL, NULL},
6072         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
6073                 0, NULL, NULL, NULL},
6074         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
6075                 0, NULL, NULL, NULL},
6076         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
6077                 0, NULL, nameUIDValidate, nameUIDPretty },
6078         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
6079                 0, NULL, NULL, NULL},
6080         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
6081                 0, NULL, numericStringValidate, NULL},
6082         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
6083                 0, NULL, NULL, NULL},
6084         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
6085                 0, NULL, numericoidValidate, NULL},
6086         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
6087                 0, NULL, IA5StringValidate, NULL},
6088         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
6089                 0, NULL, blobValidate, NULL},
6090         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
6091                 0, NULL, postalAddressValidate, NULL},
6092         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
6093                 0, NULL, NULL, NULL},
6094         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
6095                 0, NULL, NULL, NULL},
6096         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
6097                 0, NULL, printableStringValidate, NULL},
6098         /* moved here because now depends on Directory String, IA5 String 
6099          * and Printable String */
6100         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6101                 0, country_gen_syn, countryStringValidate, NULL},
6102         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
6103 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
6104                 0, NULL, subtreeSpecificationValidate, NULL},
6105         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
6106                 X_BINARY X_NOT_H_R ")",
6107                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6108         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
6109                 0, NULL, printableStringValidate, NULL},
6110         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
6111                 0, NULL, NULL, NULL},
6112         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
6113                 0, NULL, printablesStringValidate, NULL},
6114 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
6115         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
6116                 0, NULL, utcTimeValidate, NULL},
6117 #endif
6118         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
6119                 0, NULL, NULL, NULL},
6120         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
6121                 0, NULL, NULL, NULL},
6122         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
6123                 0, NULL, NULL, NULL},
6124         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
6125                 0, NULL, NULL, NULL},
6126         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
6127                 0, NULL, NULL, NULL},
6128
6129         /* RFC 2307 NIS Syntaxes */
6130         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
6131                 0, NULL, nisNetgroupTripleValidate, NULL},
6132         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
6133                 0, NULL, bootParameterValidate, NULL},
6134
6135         /* draft-zeilenga-ldap-x509 */
6136         {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
6137                 SLAP_SYNTAX_HIDE, NULL,
6138                 serialNumberAndIssuerValidate,
6139                 serialNumberAndIssuerPretty},
6140         {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
6141                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6142         {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
6143                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6144         {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
6145                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6146         {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
6147                 SLAP_SYNTAX_HIDE, NULL,
6148                 issuerAndThisUpdateValidate,
6149                 issuerAndThisUpdatePretty},
6150         {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
6151                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6152         {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
6153                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6154         {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )",
6155                 SLAP_SYNTAX_HIDE, NULL,
6156                 serialNumberAndIssuerSerialValidate,
6157                 serialNumberAndIssuerSerialPretty},
6158         {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )",
6159                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6160
6161 #ifdef SLAPD_AUTHPASSWD
6162         /* needs updating */
6163         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
6164                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6165 #endif
6166
6167         {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
6168                 0, NULL, UUIDValidate, UUIDPretty},
6169
6170         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
6171                 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
6172
6173         {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
6174                 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
6175
6176         /* OpenLDAP Void Syntax */
6177         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
6178                 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
6179
6180         /* FIXME: OID is unused, but not registered yet */
6181         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
6182                 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
6183
6184         {NULL, 0, NULL, NULL, NULL}
6185 };
6186
6187 char *csnSIDMatchSyntaxes[] = {
6188         "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
6189         NULL
6190 };
6191 char *certificateExactMatchSyntaxes[] = {
6192         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6193         NULL
6194 };
6195 char *certificateListExactMatchSyntaxes[] = {
6196         "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6197         NULL
6198 };
6199 char *attributeCertificateExactMatchSyntaxes[] = {
6200         attributeCertificateSyntaxOID  /* attributeCertificate */,
6201         NULL
6202 };
6203
6204 #ifdef LDAP_COMP_MATCH
6205 char *componentFilterMatchSyntaxes[] = {
6206         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6207         "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6208         attributeCertificateSyntaxOID /* attributeCertificate */,
6209         NULL
6210 };
6211 #endif
6212
6213 char *directoryStringSyntaxes[] = {
6214         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
6215         NULL
6216 };
6217 char *integerFirstComponentMatchSyntaxes[] = {
6218         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
6219         "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
6220         NULL
6221 };
6222 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
6223         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
6224         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
6225         "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
6226         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
6227         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
6228         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
6229         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
6230         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
6231         NULL
6232 };
6233
6234 /*
6235  * Other matching rules in X.520 that we do not use (yet):
6236  *
6237  * 2.5.13.25    uTCTimeMatch
6238  * 2.5.13.26    uTCTimeOrderingMatch
6239  * 2.5.13.31*   directoryStringFirstComponentMatch
6240  * 2.5.13.32*   wordMatch
6241  * 2.5.13.33*   keywordMatch
6242  * 2.5.13.36+   certificatePairExactMatch
6243  * 2.5.13.37+   certificatePairMatch
6244  * 2.5.13.40+   algorithmIdentifierMatch
6245  * 2.5.13.41*   storedPrefixMatch
6246  * 2.5.13.42    attributeCertificateMatch
6247  * 2.5.13.43    readerAndKeyIDMatch
6248  * 2.5.13.44    attributeIntegrityMatch
6249  *
6250  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
6251  * (+) described in draft-zeilenga-ldap-x509
6252  */
6253 static slap_mrule_defs_rec mrule_defs[] = {
6254         /*
6255          * EQUALITY matching rules must be listed after associated APPROX
6256          * matching rules.  So, we list all APPROX matching rules first.
6257          */
6258         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
6259                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6260                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6261                 NULL, NULL, directoryStringApproxMatch,
6262                 directoryStringApproxIndexer, directoryStringApproxFilter,
6263                 NULL},
6264
6265         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
6266                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6267                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6268                 NULL, NULL, IA5StringApproxMatch,
6269                 IA5StringApproxIndexer, IA5StringApproxFilter,
6270                 NULL},
6271
6272         /*
6273          * Other matching rules
6274          */
6275         
6276         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
6277                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
6278                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6279                 NULL, NULL, octetStringMatch,
6280                 octetStringIndexer, octetStringFilter,
6281                 NULL },
6282
6283         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
6284                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6285                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6286                 NULL, dnNormalize, dnMatch,
6287                 octetStringIndexer, octetStringFilter,
6288                 NULL },
6289
6290         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
6291                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6292                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6293                 NULL, dnNormalize, dnRelativeMatch,
6294                 NULL, NULL,
6295                 NULL },
6296
6297         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
6298                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6299                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6300                 NULL, dnNormalize, dnRelativeMatch,
6301                 NULL, NULL,
6302                 NULL },
6303
6304         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
6305                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6306                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6307                 NULL, dnNormalize, dnRelativeMatch,
6308                 NULL, NULL,
6309                 NULL },
6310
6311         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
6312                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6313                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6314                 NULL, dnNormalize, dnRelativeMatch,
6315                 NULL, NULL,
6316                 NULL },
6317
6318         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
6319                 "SYNTAX 1.2.36.79672281.1.5.0 )",
6320                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6321                 NULL, rdnNormalize, rdnMatch,
6322                 octetStringIndexer, octetStringFilter,
6323                 NULL },
6324
6325 #ifdef LDAP_COMP_MATCH
6326         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
6327                 "SYNTAX 1.2.36.79672281.1.5.2 )",
6328                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
6329                 NULL, NULL , componentFilterMatch,
6330                 octetStringIndexer, octetStringFilter,
6331                 NULL },
6332
6333         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
6334                 "SYNTAX 1.2.36.79672281.1.5.3 )",
6335                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6336                 NULL, NULL , allComponentsMatch,
6337                 octetStringIndexer, octetStringFilter,
6338                 NULL },
6339
6340         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
6341                 "SYNTAX 1.2.36.79672281.1.5.3 )",
6342                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6343                 NULL, NULL , directoryComponentsMatch,
6344                 octetStringIndexer, octetStringFilter,
6345                 NULL },
6346 #endif
6347
6348         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
6349                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6350                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6351                 NULL, UTF8StringNormalize, octetStringMatch,
6352                 octetStringIndexer, octetStringFilter,
6353                 directoryStringApproxMatchOID },
6354
6355         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
6356                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6357                 SLAP_MR_ORDERING, directoryStringSyntaxes,
6358                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6359                 NULL, NULL,
6360                 "caseIgnoreMatch" },
6361
6362         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
6363                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
6364                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6365                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6366                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6367                 "caseIgnoreMatch" },
6368
6369         {"( 2.5.13.5 NAME 'caseExactMatch' "
6370                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6371                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6372                 NULL, UTF8StringNormalize, octetStringMatch,
6373                 octetStringIndexer, octetStringFilter,
6374                 directoryStringApproxMatchOID },
6375
6376         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
6377                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6378                 SLAP_MR_ORDERING, directoryStringSyntaxes,
6379                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6380                 NULL, NULL,
6381                 "caseExactMatch" },
6382
6383         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
6384                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
6385                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6386                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6387                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6388                 "caseExactMatch" },
6389
6390         {"( 2.5.13.8 NAME 'numericStringMatch' "
6391                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6392                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6393                 NULL, numericStringNormalize, octetStringMatch,
6394                 octetStringIndexer, octetStringFilter,
6395                 NULL },
6396
6397         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
6398                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6399                 SLAP_MR_ORDERING, NULL,
6400                 NULL, numericStringNormalize, octetStringOrderingMatch,
6401                 NULL, NULL,
6402                 "numericStringMatch" },
6403
6404         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
6405                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
6406                 SLAP_MR_SUBSTR, NULL,
6407                 NULL, numericStringNormalize, octetStringSubstringsMatch,
6408                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6409                 "numericStringMatch" },
6410
6411         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
6412                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
6413                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6414                 NULL, postalAddressNormalize, octetStringMatch,
6415                 octetStringIndexer, octetStringFilter,
6416                 NULL },
6417
6418         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
6419                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
6420                 SLAP_MR_SUBSTR, NULL,
6421                 NULL, NULL, NULL, NULL, NULL,
6422                 "caseIgnoreListMatch" },
6423
6424         {"( 2.5.13.13 NAME 'booleanMatch' "
6425                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
6426                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6427                 NULL, NULL, booleanMatch,
6428                 octetStringIndexer, octetStringFilter,
6429                 NULL },
6430
6431         {"( 2.5.13.14 NAME 'integerMatch' "
6432                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6433                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6434                 NULL, NULL, integerMatch,
6435                 integerIndexer, integerFilter,
6436                 NULL },
6437
6438         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
6439                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6440                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
6441                 NULL, NULL, integerMatch,
6442                 NULL, NULL,
6443                 "integerMatch" },
6444
6445         {"( 2.5.13.16 NAME 'bitStringMatch' "
6446                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
6447                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6448                 NULL, NULL, octetStringMatch,
6449                 octetStringIndexer, octetStringFilter,
6450                 NULL },
6451
6452         {"( 2.5.13.17 NAME 'octetStringMatch' "
6453                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6454                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6455                 NULL, NULL, octetStringMatch,
6456                 octetStringIndexer, octetStringFilter,
6457                 NULL },
6458
6459         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
6460                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6461                 SLAP_MR_ORDERING, NULL,
6462                 NULL, NULL, octetStringOrderingMatch,
6463                 NULL, NULL,
6464                 "octetStringMatch" },
6465
6466         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
6467                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6468                 SLAP_MR_SUBSTR, NULL,
6469                 NULL, NULL, octetStringSubstringsMatch,
6470                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6471                 "octetStringMatch" },
6472
6473         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
6474                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
6475                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6476                 NULL,
6477                 telephoneNumberNormalize, octetStringMatch,
6478                 octetStringIndexer, octetStringFilter,
6479                 NULL },
6480
6481         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
6482                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
6483                 SLAP_MR_SUBSTR, NULL,
6484                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
6485                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6486                 "telephoneNumberMatch" },
6487
6488         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
6489                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
6490                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6491                 NULL, NULL, NULL, NULL, NULL, NULL },
6492
6493         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
6494                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
6495                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6496                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
6497                 uniqueMemberIndexer, uniqueMemberFilter,
6498                 NULL },
6499
6500         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
6501                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
6502                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6503                 NULL, NULL, NULL, NULL, NULL, NULL },
6504
6505         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
6506                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6507                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6508                 NULL, generalizedTimeNormalize, octetStringMatch,
6509                 generalizedTimeIndexer, generalizedTimeFilter,
6510                 NULL },
6511
6512         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
6513                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6514                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
6515                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
6516                 NULL, NULL,
6517                 "generalizedTimeMatch" },
6518
6519         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
6520                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6521                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6522                         integerFirstComponentMatchSyntaxes,
6523                 NULL, firstComponentNormalize, integerMatch,
6524                 octetStringIndexer, octetStringFilter,
6525                 NULL },
6526
6527         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
6528                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
6529                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6530                         objectIdentifierFirstComponentMatchSyntaxes,
6531                 NULL, firstComponentNormalize, octetStringMatch,
6532                 octetStringIndexer, octetStringFilter,
6533                 NULL },
6534
6535         {"( 2.5.13.34 NAME 'certificateExactMatch' "
6536                 "SYNTAX 1.3.6.1.1.15.1 )",
6537                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
6538                 NULL, certificateExactNormalize, octetStringMatch,
6539                 octetStringIndexer, octetStringFilter,
6540                 NULL },
6541
6542         {"( 2.5.13.35 NAME 'certificateMatch' "
6543                 "SYNTAX 1.3.6.1.1.15.2 )",
6544                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6545                 NULL, NULL, NULL, NULL, NULL,
6546                 NULL },
6547
6548         {"( 2.5.13.38 NAME 'certificateListExactMatch' "
6549                 "SYNTAX 1.3.6.1.1.15.5 )",
6550                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes,
6551                 NULL, certificateListExactNormalize, octetStringMatch,
6552                 octetStringIndexer, octetStringFilter,
6553                 NULL },
6554
6555         {"( 2.5.13.39 NAME 'certificateListMatch' "
6556                 "SYNTAX 1.3.6.1.1.15.6 )",
6557                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6558                 NULL, NULL, NULL, NULL, NULL,
6559                 NULL },
6560
6561         {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' "
6562                 "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )",
6563                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes,
6564                 NULL, attributeCertificateExactNormalize, octetStringMatch,
6565                 octetStringIndexer, octetStringFilter,
6566                 NULL },
6567
6568         {"( 2.5.13.46 NAME 'attributeCertificateMatch' "
6569                 "SYNTAX " attributeCertificateAssertionSyntaxOID " )",
6570                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL,
6571                 NULL, NULL, NULL, NULL, NULL,
6572                 NULL },
6573
6574         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
6575                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6576                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6577                 NULL, IA5StringNormalize, octetStringMatch,
6578                 octetStringIndexer, octetStringFilter,
6579                 IA5StringApproxMatchOID },
6580
6581         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
6582                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6583                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6584                 NULL, IA5StringNormalize, octetStringMatch,
6585                 octetStringIndexer, octetStringFilter,
6586                 IA5StringApproxMatchOID },
6587
6588         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
6589                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6590                 SLAP_MR_SUBSTR, NULL,
6591                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6592                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6593                 "caseIgnoreIA5Match" },
6594
6595         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
6596                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6597                 SLAP_MR_SUBSTR, NULL,
6598                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6599                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6600                 "caseExactIA5Match" },
6601
6602 #ifdef SLAPD_AUTHPASSWD
6603         /* needs updating */
6604         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
6605                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6606                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6607                 NULL, NULL, authPasswordMatch,
6608                 NULL, NULL,
6609                 NULL},
6610 #endif
6611
6612         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
6613                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6614                 SLAP_MR_EXT, NULL,
6615                 NULL, NULL, integerBitAndMatch,
6616                 NULL, NULL,
6617                 "integerMatch" },
6618
6619         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
6620                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6621                 SLAP_MR_EXT, NULL,
6622                 NULL, NULL, integerBitOrMatch,
6623                 NULL, NULL,
6624                 "integerMatch" },
6625
6626         {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
6627                 "SYNTAX 1.3.6.1.1.16.1 )",
6628                 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
6629                 NULL, UUIDNormalize, octetStringMatch,
6630                 octetStringIndexer, octetStringFilter,
6631                 NULL},
6632
6633         {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
6634                 "SYNTAX 1.3.6.1.1.16.1 )",
6635                 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
6636                 NULL, UUIDNormalize, octetStringOrderingMatch,
6637                 octetStringIndexer, octetStringFilter,
6638                 "UUIDMatch"},
6639
6640         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
6641                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6642                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
6643                 NULL, csnNormalize, csnMatch,
6644                 csnIndexer, csnFilter,
6645                 NULL},
6646
6647         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
6648                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6649                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
6650                 NULL, NULL, csnOrderingMatch,
6651                 NULL, NULL,
6652                 "CSNMatch" },
6653
6654         {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
6655                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
6656                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
6657                 NULL, csnSidNormalize, octetStringMatch,
6658                 octetStringIndexer, octetStringFilter,
6659                 NULL },
6660
6661         /* FIXME: OID is unused, but not registered yet */
6662         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
6663                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
6664                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6665                 NULL, authzNormalize, authzMatch,
6666                 NULL, NULL,
6667                 NULL},
6668
6669         {NULL, SLAP_MR_NONE, NULL,
6670                 NULL, NULL, NULL, NULL, NULL,
6671                 NULL }
6672 };
6673
6674 int
6675 slap_schema_init( void )
6676 {
6677         int             res;
6678         int             i;
6679
6680         /* we should only be called once (from main) */
6681         assert( schema_init_done == 0 );
6682
6683         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
6684                 res = register_syntax( &syntax_defs[i] );
6685
6686                 if ( res ) {
6687                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
6688                                  syntax_defs[i].sd_desc );
6689                         return LDAP_OTHER;
6690                 }
6691         }
6692
6693         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
6694                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
6695                         mrule_defs[i].mrd_compat_syntaxes == NULL )
6696                 {
6697                         fprintf( stderr,
6698                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
6699                                  mrule_defs[i].mrd_desc );
6700                         continue;
6701                 }
6702
6703                 res = register_matching_rule( &mrule_defs[i] );
6704
6705                 if ( res ) {
6706                         fprintf( stderr,
6707                                 "slap_schema_init: Error registering matching rule %s\n",
6708                                  mrule_defs[i].mrd_desc );
6709                         return LDAP_OTHER;
6710                 }
6711         }
6712
6713         res = slap_schema_load();
6714         schema_init_done = 1;
6715         return res;
6716 }
6717
6718 void
6719 schema_destroy( void )
6720 {
6721         oidm_destroy();
6722         oc_destroy();
6723         at_destroy();
6724         mr_destroy();
6725         mru_destroy();
6726         syn_destroy();
6727
6728         if( schema_init_done ) {
6729                 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
6730                 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
6731         }
6732 }