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