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