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