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