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