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