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