]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
Merge remote-tracking branch 'origin/mdb.master' into OPENLDAP_REL_ENG_2_4
[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-2013 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         len = ber_ptrlen( ber );
3672         bvdn.bv_val = val->bv_val + len;
3673         bvdn.bv_len = val->bv_len - len;
3674
3675         rc = dnX509normalize( &bvdn, &issuer_dn );
3676         if ( rc != LDAP_SUCCESS ) goto done;
3677
3678         normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3679                 + sn2.bv_len + issuer_dn.bv_len;
3680         normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
3681
3682         p = normalized->bv_val;
3683
3684         p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3685         p = lutil_strbvcopy( p, &sn2 );
3686         p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3687         p = lutil_strbvcopy( p, &issuer_dn );
3688         p = lutil_strcopy( p, /*{*/ "\" }" );
3689
3690         rc = LDAP_SUCCESS;
3691
3692 done:
3693         Debug( LDAP_DEBUG_TRACE, "<<< certificateExactNormalize: <%p, %lu> => <%s>\n",
3694                 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
3695
3696         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3697         if ( sn2.bv_val != serialbuf2 ) ber_memfree_x( sn2.bv_val, ctx );
3698
3699         return rc;
3700 }
3701
3702 /* X.509 PKI certificateList stuff */
3703 static int
3704 checkTime( struct berval *in, struct berval *out )
3705 {
3706         int rc;
3707         ber_len_t i;
3708         char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3709         struct berval bv;
3710
3711         assert( in != NULL );
3712         assert( !BER_BVISNULL( in ) );
3713         assert( !BER_BVISEMPTY( in ) );
3714
3715         if ( in->bv_len < STRLENOF( "YYmmddHHMMSSZ" ) ) {
3716                 return -1;
3717         }
3718
3719         if ( out != NULL ) {
3720                 assert( !BER_BVISNULL( out ) );
3721                 assert( out->bv_len >= sizeof( buf ) );
3722                 bv.bv_val = out->bv_val;
3723
3724         } else {
3725                 bv.bv_val = buf;
3726         }
3727
3728         for ( i = 0; i < STRLENOF( "YYYYmmddHHMMSS" ); i++ ) {
3729                 if ( !ASCII_DIGIT( in->bv_val[i] ) ) break;
3730         }
3731
3732         if ( in->bv_val[i] != 'Z' ) {
3733                 return -1;
3734         }
3735         i++;
3736
3737         if ( i != in->bv_len ) {
3738                 return -1;
3739         }
3740
3741         if ( i == STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3742                 lutil_strncopy( bv.bv_val, in->bv_val, i );
3743                 bv.bv_len = i;
3744                 
3745         } else if ( i == STRLENOF( "YYmmddHHMMSSZ" ) ) {
3746                 char *p = bv.bv_val;
3747                 if ( in->bv_val[0] < '7' ) {
3748                         p = lutil_strcopy( p, "20" );
3749
3750                 } else {
3751                         p = lutil_strcopy( p, "19" );
3752                 }
3753                 lutil_strncopy( p, in->bv_val, i );
3754                 bv.bv_len = 2 + i;
3755
3756         } else {
3757                 return -1;
3758         }
3759
3760         rc = generalizedTimeValidate( NULL, &bv );
3761         if ( rc == LDAP_SUCCESS && out != NULL ) {
3762                 if ( out->bv_len > bv.bv_len ) {
3763                         out->bv_val[ bv.bv_len ] = '\0';
3764                 }
3765                 out->bv_len = bv.bv_len;
3766         }
3767
3768         return rc != LDAP_SUCCESS;
3769 }
3770
3771 static int
3772 issuerAndThisUpdateCheck(
3773         struct berval *in,
3774         struct berval *is,
3775         struct berval *tu,
3776         void *ctx )
3777 {
3778         int numdquotes = 0;
3779         struct berval x = *in;
3780         struct berval ni = BER_BVNULL;
3781         /* Parse GSER format */ 
3782         enum {
3783                 HAVE_NONE = 0x0,
3784                 HAVE_ISSUER = 0x1,
3785                 HAVE_THISUPDATE = 0x2,
3786                 HAVE_ALL = ( HAVE_ISSUER | HAVE_THISUPDATE )
3787         } have = HAVE_NONE;
3788
3789
3790         if ( in->bv_len < STRLENOF( "{issuer \"\",thisUpdate \"YYMMDDhhmmssZ\"}" ) ) return LDAP_INVALID_SYNTAX;
3791
3792         if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3793                 return LDAP_INVALID_SYNTAX;
3794         }
3795
3796         x.bv_val++;
3797         x.bv_len -= STRLENOF("{}");
3798
3799         do {
3800                 /* eat leading spaces */
3801                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3802                         /* empty */;
3803                 }
3804
3805                 /* should be at issuer or thisUpdate */
3806                 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3807                         if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3808
3809                         /* parse issuer */
3810                         x.bv_val += STRLENOF("issuer");
3811                         x.bv_len -= STRLENOF("issuer");
3812
3813                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3814                         x.bv_val++;
3815                         x.bv_len--;
3816
3817                         /* eat leading spaces */
3818                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3819                                 /* empty */;
3820                         }
3821
3822                         /* For backward compatibility, this part is optional */
3823                         if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) != 0 ) {
3824                                 return LDAP_INVALID_SYNTAX;
3825                         }
3826                         x.bv_val += STRLENOF("rdnSequence:");
3827                         x.bv_len -= STRLENOF("rdnSequence:");
3828
3829                         if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3830                         x.bv_val++;
3831                         x.bv_len--;
3832
3833                         is->bv_val = x.bv_val;
3834                         is->bv_len = 0;
3835
3836                         for ( ; is->bv_len < x.bv_len; ) {
3837                                 if ( is->bv_val[is->bv_len] != '"' ) {
3838                                         is->bv_len++;
3839                                         continue;
3840                                 }
3841                                 if ( is->bv_val[is->bv_len+1] == '"' ) {
3842                                         /* double dquote */
3843                                         is->bv_len += 2;
3844                                         continue;
3845                                 }
3846                                 break;
3847                         }
3848                         x.bv_val += is->bv_len + 1;
3849                         x.bv_len -= is->bv_len + 1;
3850
3851                         have |= HAVE_ISSUER;
3852
3853                 } else if ( strncasecmp( x.bv_val, "thisUpdate", STRLENOF("thisUpdate") ) == 0 )
3854                 {
3855                         if ( have & HAVE_THISUPDATE ) return LDAP_INVALID_SYNTAX;
3856
3857                         /* parse thisUpdate */
3858                         x.bv_val += STRLENOF("thisUpdate");
3859                         x.bv_len -= STRLENOF("thisUpdate");
3860
3861                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3862                         x.bv_val++;
3863                         x.bv_len--;
3864
3865                         /* eat leading spaces */
3866                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3867                                 /* empty */;
3868                         }
3869
3870                         if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3871                         x.bv_val++;
3872                         x.bv_len--;
3873
3874                         tu->bv_val = x.bv_val;
3875                         tu->bv_len = 0;
3876
3877                         for ( ; tu->bv_len < x.bv_len; tu->bv_len++ ) {
3878                                 if ( tu->bv_val[tu->bv_len] == '"' ) {
3879                                         break;
3880                                 }
3881                         }
3882                         x.bv_val += tu->bv_len + 1;
3883                         x.bv_len -= tu->bv_len + 1;
3884
3885                         have |= HAVE_THISUPDATE;
3886
3887                 } else {
3888                         return LDAP_INVALID_SYNTAX;
3889                 }
3890
3891                 /* eat leading spaces */
3892                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3893                         /* empty */;
3894                 }
3895
3896                 if ( have == HAVE_ALL ) {
3897                         break;
3898                 }
3899
3900                 if ( x.bv_val[0] != ',' ) {
3901                         return LDAP_INVALID_SYNTAX;
3902                 }
3903
3904                 x.bv_val++;
3905                 x.bv_len--;
3906         } while ( 1 );
3907
3908         /* should have no characters left... */
3909         if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3910
3911         if ( numdquotes == 0 ) {
3912                 ber_dupbv_x( &ni, is, ctx );
3913
3914         } else {
3915                 ber_len_t src, dst;
3916
3917                 ni.bv_len = is->bv_len - numdquotes;
3918                 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3919                 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3920                         if ( is->bv_val[src] == '"' ) {
3921                                 src++;
3922                         }
3923                         ni.bv_val[dst] = is->bv_val[src];
3924                 }
3925                 ni.bv_val[dst] = '\0';
3926         }
3927                 
3928         *is = ni;
3929
3930         return 0;
3931 }
3932
3933 static int
3934 issuerAndThisUpdateValidate(
3935         Syntax *syntax,
3936         struct berval *in )
3937 {
3938         int rc;
3939         struct berval i, tu;
3940
3941         Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateValidate: <%s>\n",
3942                 in->bv_val, 0, 0 );
3943
3944         rc = issuerAndThisUpdateCheck( in, &i, &tu, NULL );
3945         if ( rc ) {
3946                 goto done;
3947         }
3948
3949         /* validate DN -- doesn't handle double dquote */ 
3950         rc = dnValidate( NULL, &i );
3951         if ( rc ) {
3952                 rc = LDAP_INVALID_SYNTAX;
3953
3954         } else if ( checkTime( &tu, NULL ) ) {
3955                 rc = LDAP_INVALID_SYNTAX;
3956         }
3957
3958         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3959                 slap_sl_free( i.bv_val, NULL );
3960         }
3961
3962         Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateValidate: <%s> err=%d\n",
3963                 in->bv_val, rc, 0 );
3964
3965 done:;
3966         return rc;
3967 }
3968
3969 static int
3970 issuerAndThisUpdatePretty(
3971         Syntax *syntax,
3972         struct berval *in,
3973         struct berval *out,
3974         void *ctx )
3975 {
3976         int rc;
3977         struct berval i, tu, ni = BER_BVNULL;
3978         char *p;
3979
3980         assert( in != NULL );
3981         assert( out != NULL );
3982
3983         BER_BVZERO( out );
3984
3985         Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdatePretty: <%s>\n",
3986                 in->bv_val, 0, 0 );
3987
3988         rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
3989         if ( rc ) {
3990                 goto done;
3991         }
3992
3993         rc = dnPretty( syntax, &i, &ni, ctx );
3994
3995         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3996                 slap_sl_free( i.bv_val, ctx );
3997         }
3998
3999         if ( rc || checkTime( &tu, NULL ) ) {
4000                 rc = LDAP_INVALID_SYNTAX;
4001                 goto done;
4002         }
4003
4004         /* make room */
4005         out->bv_len = STRLENOF("{ issuer rdnSequence:\"\", thisUpdate \"\" }")
4006                 + ni.bv_len + tu.bv_len;
4007         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4008
4009         if ( out->bv_val == NULL ) {
4010                 out->bv_len = 0;
4011                 rc = LDAP_OTHER;
4012                 goto done;
4013         }
4014
4015         p = out->bv_val;
4016         p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4017         p = lutil_strbvcopy( p, &ni );
4018         p = lutil_strcopy( p, "\", thisUpdate \"" );
4019         p = lutil_strbvcopy( p, &tu );
4020         p = lutil_strcopy( p, /*{*/ "\" }" );
4021
4022         assert( p == &out->bv_val[out->bv_len] );
4023
4024 done:;
4025         Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n",
4026                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4027
4028         slap_sl_free( ni.bv_val, ctx );
4029
4030         return rc; 
4031 }
4032
4033 static int
4034 issuerAndThisUpdateNormalize(
4035         slap_mask_t usage,
4036         Syntax *syntax,
4037         MatchingRule *mr,
4038         struct berval *in,
4039         struct berval *out,
4040         void *ctx )
4041 {
4042         struct berval i, ni, tu, tu2;
4043         char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4044         char *p;
4045         int rc;
4046
4047         assert( in != NULL );
4048         assert( out != NULL );
4049
4050         Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
4051                 in->bv_val, 0, 0 );
4052
4053         rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4054         if ( rc ) {
4055                 return rc;
4056         }
4057
4058         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4059
4060         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4061                 slap_sl_free( i.bv_val, ctx );
4062         }
4063
4064         tu2.bv_val = sbuf;
4065         tu2.bv_len = sizeof( sbuf );
4066         if ( rc || checkTime( &tu, &tu2 ) ) {
4067                 return LDAP_INVALID_SYNTAX;
4068         }
4069
4070         out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4071                 + ni.bv_len + tu2.bv_len;
4072         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4073
4074         if ( out->bv_val == NULL ) {
4075                 out->bv_len = 0;
4076                 rc = LDAP_OTHER;
4077                 goto func_leave;
4078         }
4079
4080         p = out->bv_val;
4081
4082         p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4083         p = lutil_strbvcopy( p, &ni );
4084         p = lutil_strcopy( p, "\", thisUpdate \"" );
4085         p = lutil_strbvcopy( p, &tu2 );
4086         p = lutil_strcopy( p, /*{*/ "\" }" );
4087
4088         assert( p == &out->bv_val[out->bv_len] );
4089
4090 func_leave:
4091         Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
4092                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4093
4094         slap_sl_free( ni.bv_val, ctx );
4095
4096         return rc;
4097 }
4098
4099 static int
4100 certificateListExactNormalize(
4101         slap_mask_t usage,
4102         Syntax *syntax,
4103         MatchingRule *mr,
4104         struct berval *val,
4105         struct berval *normalized,
4106         void *ctx )
4107 {
4108         BerElementBuffer berbuf;
4109         BerElement *ber = (BerElement *)&berbuf;
4110         ber_tag_t tag;
4111         ber_len_t len;
4112         ber_int_t version;
4113         struct berval issuer_dn = BER_BVNULL, bvdn,
4114                 thisUpdate, bvtu;
4115         char *p, tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4116         int rc = LDAP_INVALID_SYNTAX;
4117
4118         assert( val != NULL );
4119
4120         Debug( LDAP_DEBUG_TRACE, ">>> certificateListExactNormalize: <%p, %lu>\n",
4121                 val->bv_val, val->bv_len, 0 );
4122
4123         if ( BER_BVISEMPTY( val ) ) goto done;
4124
4125         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4126                 return issuerAndThisUpdateNormalize( 0, NULL, NULL, val, normalized, ctx );
4127         }
4128
4129         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4130
4131         ber_init2( ber, val, LBER_USE_DER );
4132         tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
4133         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4134         tag = ber_skip_tag( ber, &len );        /* Sequence */
4135         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4136         tag = ber_peek_tag( ber, &len );
4137         /* Optional version */
4138         if ( tag == LBER_INTEGER ) {
4139                 tag = ber_get_int( ber, &version );
4140                 assert( tag == LBER_INTEGER );
4141                 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
4142         }
4143         tag = ber_skip_tag( ber, &len );        /* Signature Algorithm */
4144         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4145         ber_skip_data( ber, len );
4146
4147         tag = ber_peek_tag( ber, &len );        /* IssuerDN */
4148         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4149         len = ber_ptrlen( ber );
4150         bvdn.bv_val = val->bv_val + len;
4151         bvdn.bv_len = val->bv_len - len;
4152         tag = ber_skip_tag( ber, &len );
4153         ber_skip_data( ber, len );
4154
4155         tag = ber_skip_tag( ber, &len );        /* thisUpdate */
4156         /* Time is a CHOICE { UTCTime, GeneralizedTime } */
4157         if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
4158         bvtu.bv_val = (char *)ber->ber_ptr;
4159         bvtu.bv_len = len;
4160
4161         rc = dnX509normalize( &bvdn, &issuer_dn );
4162         if ( rc != LDAP_SUCCESS ) goto done;
4163
4164         thisUpdate.bv_val = tubuf;
4165         thisUpdate.bv_len = sizeof(tubuf);
4166         if ( checkTime( &bvtu, &thisUpdate ) ) {
4167                 rc = LDAP_INVALID_SYNTAX;
4168                 goto done;
4169         }
4170
4171         normalized->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4172                 + issuer_dn.bv_len + thisUpdate.bv_len;
4173         normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4174
4175         p = normalized->bv_val;
4176
4177         p = lutil_strcopy( p, "{ issuer rdnSequence:\"" );
4178         p = lutil_strbvcopy( p, &issuer_dn );
4179         p = lutil_strcopy( p, "\", thisUpdate \"" );
4180         p = lutil_strbvcopy( p, &thisUpdate );
4181         p = lutil_strcopy( p, /*{*/ "\" }" );
4182
4183         rc = LDAP_SUCCESS;
4184
4185 done:
4186         Debug( LDAP_DEBUG_TRACE, "<<< certificateListExactNormalize: <%p, %lu> => <%s>\n",
4187                 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
4188
4189         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4190
4191         return rc;
4192 }
4193
4194 /* X.509 PMI serialNumberAndIssuerSerialCheck
4195
4196 AttributeCertificateExactAssertion     ::= SEQUENCE {
4197    serialNumber              CertificateSerialNumber,
4198    issuer                    AttCertIssuer }
4199
4200 CertificateSerialNumber ::= INTEGER
4201
4202 AttCertIssuer ::=    [0] SEQUENCE {
4203 issuerName                     GeneralNames OPTIONAL,
4204 baseCertificateID         [0] IssuerSerial OPTIONAL,
4205 objectDigestInfo          [1] ObjectDigestInfo OPTIONAL }
4206 -- At least one component shall be present
4207
4208 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
4209
4210 GeneralName ::= CHOICE {
4211   otherName                 [0] INSTANCE OF OTHER-NAME,
4212   rfc822Name                [1] IA5String,
4213   dNSName                   [2] IA5String,
4214   x400Address               [3] ORAddress,
4215   directoryName             [4] Name,
4216   ediPartyName              [5] EDIPartyName,
4217   uniformResourceIdentifier [6] IA5String,
4218   iPAddress                 [7] OCTET STRING,
4219   registeredID              [8] OBJECT IDENTIFIER }
4220
4221 IssuerSerial ::= SEQUENCE {
4222    issuer       GeneralNames,
4223    serial       CertificateSerialNumber,
4224    issuerUID UniqueIdentifier OPTIONAL }
4225
4226 ObjectDigestInfo ::= SEQUENCE {
4227    digestedObjectType ENUMERATED {
4228       publicKey           (0),
4229       publicKeyCert       (1),
4230       otherObjectTypes    (2) },
4231    otherObjectTypeID      OBJECT IDENTIFIER OPTIONAL,
4232    digestAlgorithm        AlgorithmIdentifier,
4233    objectDigest           BIT STRING }
4234
4235  * The way I interpret it, an assertion should look like
4236
4237  { serialNumber 'dd'H,
4238    issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional
4239             baseCertificateID { serial '1d'H,
4240                                 issuer { directoryName:rdnSequence:"cn=zzz" },
4241                                 issuerUID <value>              -- optional
4242                               },                               -- optional
4243             objectDigestInfo { ... }                           -- optional
4244           }
4245  }
4246  
4247  * with issuerName, baseCertificateID and objectDigestInfo optional,
4248  * at least one present; the way it's currently implemented, it is
4249
4250  { serialNumber 'dd'H,
4251    issuer { baseCertificateID { serial '1d'H,
4252                                 issuer { directoryName:rdnSequence:"cn=zzz" }
4253                               }
4254           }
4255  }
4256
4257  * with all the above parts mandatory.
4258  */
4259 static int
4260 serialNumberAndIssuerSerialCheck(
4261         struct berval *in,
4262         struct berval *sn,
4263         struct berval *is,
4264         struct berval *i_sn,    /* contain serial of baseCertificateID */
4265         void *ctx )
4266 {
4267         /* Parse GSER format */ 
4268         enum {
4269                 HAVE_NONE = 0x0,
4270                 HAVE_SN = 0x1,
4271                 HAVE_ISSUER = 0x2,
4272                 HAVE_ALL = ( HAVE_SN | HAVE_ISSUER )
4273         } have = HAVE_NONE, have2 = HAVE_NONE;
4274         int numdquotes = 0;
4275         struct berval x = *in;
4276         struct berval ni;
4277
4278         if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4279
4280         /* no old format */
4281         if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX;
4282
4283         x.bv_val++;
4284         x.bv_len -= 2;
4285
4286         do {
4287
4288                 /* eat leading spaces */
4289                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4290                         /* empty */;
4291                 }
4292
4293                 /* should be at issuer or serialNumber NamedValue */
4294                 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
4295                         if ( have & HAVE_ISSUER ) {
4296                                 return LDAP_INVALID_SYNTAX;
4297                         }
4298
4299                         /* parse IssuerSerial */
4300                         x.bv_val += STRLENOF("issuer");
4301                         x.bv_len -= STRLENOF("issuer");
4302
4303                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4304                         x.bv_val++;
4305                         x.bv_len--;
4306
4307                         /* eat leading spaces */
4308                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4309                                 /* empty */;
4310                         }
4311
4312                         if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4313                         x.bv_val++;
4314                         x.bv_len--;
4315
4316                         /* eat leading spaces */
4317                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4318                                 /* empty */;
4319                         }
4320
4321                         if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) {
4322                                 return LDAP_INVALID_SYNTAX;
4323                         }
4324                         x.bv_val += STRLENOF("baseCertificateID ");
4325                         x.bv_len -= STRLENOF("baseCertificateID ");
4326
4327                         /* eat leading spaces */
4328                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4329                                 /* empty */;
4330                         }
4331
4332                         if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4333                         x.bv_val++;
4334                         x.bv_len--;
4335
4336                         do {
4337                                 /* eat leading spaces */
4338                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4339                                         /* empty */;
4340                                 }
4341
4342                                 /* parse issuer of baseCertificateID */
4343                                 if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) {
4344                                         if ( have2 & HAVE_ISSUER ) {
4345                                                 return LDAP_INVALID_SYNTAX;
4346                                         }
4347
4348                                         x.bv_val += STRLENOF("issuer ");
4349                                         x.bv_len -= STRLENOF("issuer ");
4350
4351                                         /* eat leading spaces */
4352                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4353                                                 /* empty */;
4354                                         }
4355
4356                                         if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4357                                         x.bv_val++;
4358                                         x.bv_len--;
4359
4360                                         /* eat leading spaces */
4361                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4362                                                 /* empty */;
4363                                         }
4364
4365                                         if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) {
4366                                                 return LDAP_INVALID_SYNTAX;
4367                                         }
4368                                         x.bv_val += STRLENOF("directoryName:rdnSequence:");
4369                                         x.bv_len -= STRLENOF("directoryName:rdnSequence:");
4370
4371                                         if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
4372                                         x.bv_val++;
4373                                         x.bv_len--;
4374
4375                                         is->bv_val = x.bv_val;
4376                                         is->bv_len = 0;
4377
4378                                         for ( ; is->bv_len < x.bv_len; ) {
4379                                                 if ( is->bv_val[is->bv_len] != '"' ) {
4380                                                         is->bv_len++;
4381                                                         continue;
4382                                                 }
4383                                                 if ( is->bv_val[is->bv_len + 1] == '"' ) {
4384                                                         /* double dquote */
4385                                                         is->bv_len += 2;
4386                                                         continue;
4387                                                 }
4388                                                 break;
4389                                         }
4390                                         x.bv_val += is->bv_len + 1;
4391                                         x.bv_len -= is->bv_len + 1;
4392
4393                                         /* eat leading spaces */
4394                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4395                                                 /* empty */;
4396                                         }
4397
4398                                         if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4399                                         x.bv_val++;
4400                                         x.bv_len--;
4401
4402                                         have2 |= HAVE_ISSUER;
4403
4404                                 } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) {
4405                                         if ( have2 & HAVE_SN ) {
4406                                                 return LDAP_INVALID_SYNTAX;
4407                                         }
4408
4409                                         x.bv_val += STRLENOF("serial ");
4410                                         x.bv_len -= STRLENOF("serial ");
4411
4412                                         /* eat leading spaces */
4413                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
4414                                                 /* empty */;
4415                                         }
4416
4417                                         if ( checkNum( &x, i_sn ) ) {
4418                                                 return LDAP_INVALID_SYNTAX;
4419                                         }
4420
4421                                         x.bv_val += i_sn->bv_len;
4422                                         x.bv_len -= i_sn->bv_len;
4423
4424                                         have2 |= HAVE_SN;
4425
4426                                 } else {
4427                                         return LDAP_INVALID_SYNTAX;
4428                                 }
4429
4430                                 /* eat leading spaces */
4431                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4432                                         /* empty */;
4433                                 }
4434
4435                                 if ( have2 == HAVE_ALL ) {
4436                                         break;
4437                                 }
4438
4439                                 if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
4440                                 x.bv_val++;
4441                                 x.bv_len--;
4442                         } while ( 1 );
4443
4444                         if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4445                         x.bv_val++;
4446                         x.bv_len--;
4447
4448                         /* eat leading spaces */
4449                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4450                                 /* empty */;
4451                         }
4452
4453                         if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4454                         x.bv_val++;
4455                         x.bv_len--;
4456
4457                         have |= HAVE_ISSUER;
4458
4459                 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) {
4460                         if ( have & HAVE_SN ) {
4461                                 return LDAP_INVALID_SYNTAX;
4462                         }
4463
4464                         /* parse serialNumber */
4465                         x.bv_val += STRLENOF("serialNumber");
4466                         x.bv_len -= STRLENOF("serialNumber");
4467
4468                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4469                         x.bv_val++;
4470                         x.bv_len--;
4471
4472                         /* eat leading spaces */
4473                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4474                                 /* empty */;
4475                         }
4476                         
4477                         if ( checkNum( &x, sn ) ) {
4478                                 return LDAP_INVALID_SYNTAX;
4479                         }
4480
4481                         x.bv_val += sn->bv_len;
4482                         x.bv_len -= sn->bv_len;
4483
4484                         have |= HAVE_SN;
4485
4486                 } else {
4487                         return LDAP_INVALID_SYNTAX;
4488                 }
4489
4490                 /* eat spaces */
4491                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4492                         /* empty */;
4493                 }
4494
4495                 if ( have == HAVE_ALL ) {
4496                         break;
4497                 }
4498
4499                 if ( x.bv_val[0] != ',' ) {
4500                         return LDAP_INVALID_SYNTAX;
4501                 }
4502                 x.bv_val++ ;
4503                 x.bv_len--;
4504         } while ( 1 );
4505
4506         /* should have no characters left... */
4507         if( x.bv_len ) return LDAP_INVALID_SYNTAX;
4508
4509         if ( numdquotes == 0 ) {
4510                 ber_dupbv_x( &ni, is, ctx );
4511
4512         } else {
4513                 ber_len_t src, dst;
4514
4515                 ni.bv_len = is->bv_len - numdquotes;
4516                 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
4517                 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
4518                         if ( is->bv_val[src] == '"' ) {
4519                                 src++;
4520                         }
4521                         ni.bv_val[dst] = is->bv_val[src];
4522                 }
4523                 ni.bv_val[dst] = '\0';
4524         }
4525
4526         *is = ni;
4527
4528         /* need to handle double dquotes here */
4529         return 0;
4530 }
4531
4532 /* X.509 PMI serialNumberAndIssuerSerialValidate */
4533 static int
4534 serialNumberAndIssuerSerialValidate(
4535         Syntax *syntax,
4536         struct berval *in )
4537 {
4538         int rc;
4539         struct berval sn, i, i_sn;
4540
4541         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n",
4542                 in->bv_val, 0, 0 );
4543
4544         rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL );
4545         if ( rc ) {
4546                 goto done;
4547         }
4548
4549         /* validate DN -- doesn't handle double dquote */ 
4550         rc = dnValidate( NULL, &i );
4551         if ( rc ) {
4552                 rc = LDAP_INVALID_SYNTAX;
4553         }
4554
4555         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4556                 slap_sl_free( i.bv_val, NULL );
4557         }
4558
4559 done:;
4560         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n",
4561                 in->bv_val, rc, 0 );
4562
4563         return rc;
4564 }
4565
4566 /* X.509 PMI serialNumberAndIssuerSerialPretty */
4567 static int
4568 serialNumberAndIssuerSerialPretty(
4569         Syntax *syntax,
4570         struct berval *in,
4571         struct berval *out,
4572         void *ctx )
4573 {
4574         struct berval sn, i, i_sn, ni = BER_BVNULL;
4575         char *p;
4576         int rc;
4577
4578         assert( in != NULL );
4579         assert( out != NULL );
4580
4581         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n",
4582                 in->bv_val, 0, 0 );
4583
4584         rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4585         if ( rc ) {
4586                 goto done;
4587         }
4588
4589         rc = dnPretty( syntax, &i, &ni, ctx );
4590
4591         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4592                 slap_sl_free( i.bv_val, ctx );
4593         }
4594
4595         if ( rc ) {
4596                 rc = LDAP_INVALID_SYNTAX;
4597                 goto done;
4598         }
4599
4600         /* make room from sn + "$" */
4601         out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }")
4602                 + sn.bv_len + ni.bv_len + i_sn.bv_len;
4603         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4604
4605         if ( out->bv_val == NULL ) {
4606                 out->bv_len = 0;
4607                 rc = LDAP_OTHER;
4608                 goto done;
4609         }
4610
4611         p = out->bv_val;
4612         p = lutil_strcopy( p, "{ serialNumber " );
4613         p = lutil_strbvcopy( p, &sn );
4614         p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4615         p = lutil_strbvcopy( p, &ni );
4616         p = lutil_strcopy( p, "\" }, serial " );
4617         p = lutil_strbvcopy( p, &i_sn );
4618         p = lutil_strcopy( p, " } } }" );
4619
4620         assert( p == &out->bv_val[out->bv_len] );
4621
4622 done:;
4623         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n",
4624                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4625
4626         slap_sl_free( ni.bv_val, ctx );
4627
4628         return rc; 
4629 }
4630
4631 /* X.509 PMI serialNumberAndIssuerSerialNormalize */
4632 /*
4633  * This routine is called by attributeCertificateExactNormalize
4634  * when attributeCertificateExactNormalize receives a search 
4635  * string instead of a attribute certificate. This routine 
4636  * checks if the search value is valid and then returns the 
4637  * normalized value
4638  */
4639 static int
4640 serialNumberAndIssuerSerialNormalize(
4641         slap_mask_t usage,
4642         Syntax *syntax,
4643         MatchingRule *mr,
4644         struct berval *in,
4645         struct berval *out,
4646         void *ctx )
4647 {
4648         struct berval i, ni = BER_BVNULL,
4649                 sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL,
4650                 i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL;
4651         char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN],
4652                 sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN];
4653         char *p;
4654         int rc;
4655
4656         assert( in != NULL );
4657         assert( out != NULL );
4658
4659         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n",
4660                 in->bv_val, 0, 0 );
4661
4662         rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4663         if ( rc ) {
4664                 goto func_leave;
4665         }
4666
4667         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4668
4669         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4670                 slap_sl_free( i.bv_val, ctx );
4671         }
4672
4673         if ( rc ) {
4674                 rc = LDAP_INVALID_SYNTAX;
4675                 goto func_leave;
4676         }
4677
4678         /* Convert sn to canonical hex */
4679         sn2.bv_val = sbuf2;
4680         sn2.bv_len = sn.bv_len;
4681         if ( sn.bv_len > sizeof( sbuf2 ) ) {
4682                 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
4683         }
4684         if ( lutil_str2bin( &sn, &sn2, ctx ) ) {
4685                 rc = LDAP_INVALID_SYNTAX;
4686                 goto func_leave;
4687         }
4688
4689         /* Convert i_sn to canonical hex */
4690         i_sn2.bv_val = i_sbuf2;
4691         i_sn2.bv_len = i_sn.bv_len;
4692         if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) {
4693                 i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx );
4694         }
4695         if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) {
4696                 rc = LDAP_INVALID_SYNTAX;
4697                 goto func_leave;
4698         }
4699
4700         sn3.bv_val = sbuf3;
4701         sn3.bv_len = sizeof(sbuf3);
4702         if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
4703                 rc = LDAP_INVALID_SYNTAX;
4704                 goto func_leave;
4705         }
4706
4707         i_sn3.bv_val = i_sbuf3;
4708         i_sn3.bv_len = sizeof(i_sbuf3);
4709         if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) {
4710                 rc = LDAP_INVALID_SYNTAX;
4711                 goto func_leave;
4712         }
4713
4714         out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }")
4715                 + sn3.bv_len + ni.bv_len + i_sn3.bv_len;
4716         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4717
4718         if ( out->bv_val == NULL ) {
4719                 out->bv_len = 0;
4720                 rc = LDAP_OTHER;
4721                 goto func_leave;
4722         }
4723
4724         p = out->bv_val;
4725
4726         p = lutil_strcopy( p, "{ serialNumber " );
4727         p = lutil_strbvcopy( p, &sn3 );
4728         p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4729         p = lutil_strbvcopy( p, &ni );
4730         p = lutil_strcopy( p, "\" }, serial " );
4731         p = lutil_strbvcopy( p, &i_sn3 );
4732         p = lutil_strcopy( p, " } } }" );
4733
4734         assert( p == &out->bv_val[out->bv_len] );
4735
4736 func_leave:
4737         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n",
4738                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4739
4740         if ( sn2.bv_val != sbuf2 ) {
4741                 slap_sl_free( sn2.bv_val, ctx );
4742         }
4743
4744         if ( i_sn2.bv_val != i_sbuf2 ) {
4745                 slap_sl_free( i_sn2.bv_val, ctx );
4746         }
4747
4748         if ( sn3.bv_val != sbuf3 ) {
4749                 slap_sl_free( sn3.bv_val, ctx );
4750         }
4751
4752         if ( i_sn3.bv_val != i_sbuf3 ) {
4753                 slap_sl_free( i_sn3.bv_val, ctx );
4754         }
4755
4756         slap_sl_free( ni.bv_val, ctx );
4757
4758         return rc;
4759 }
4760
4761 /* X.509 PMI attributeCertificateExactNormalize */
4762 static int
4763 attributeCertificateExactNormalize(
4764         slap_mask_t usage,
4765         Syntax *syntax,
4766         MatchingRule *mr,
4767         struct berval *val,
4768         struct berval *normalized,
4769         void *ctx )
4770 {
4771         BerElementBuffer berbuf;
4772         BerElement *ber = (BerElement *)&berbuf;
4773         ber_tag_t tag;
4774         ber_len_t len;
4775         char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN];
4776         struct berval sn, i_sn, sn2 = BER_BVNULL, i_sn2 = BER_BVNULL;
4777         struct berval issuer_dn = BER_BVNULL, bvdn;
4778         char *p;
4779         int rc = LDAP_INVALID_SYNTAX;
4780
4781         if ( BER_BVISEMPTY( val ) ) {
4782                 return rc;
4783         }
4784
4785         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4786                 return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx );
4787         }
4788
4789         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4790
4791         ber_init2( ber, val, LBER_USE_DER );
4792         tag = ber_skip_tag( ber, &len );        /* Signed Sequence */
4793         tag = ber_skip_tag( ber, &len );        /* Sequence */
4794         tag = ber_skip_tag( ber, &len );        /* (Mandatory) version; must be v2(1) */
4795         ber_skip_data( ber, len );
4796         tag = ber_skip_tag( ber, &len );        /* Holder Sequence */
4797         ber_skip_data( ber, len );
4798
4799         /* Issuer */
4800         tag = ber_skip_tag( ber, &len );        /* Sequence */
4801                                                 /* issuerName (GeneralNames sequence; optional)? */
4802         tag = ber_skip_tag( ber, &len );        /* baseCertificateID (sequence; optional)? */
4803         tag = ber_skip_tag( ber, &len );        /* GeneralNames (sequence) */
4804         tag = ber_skip_tag( ber, &len );        /* directoryName (we only accept this form of GeneralName) */
4805         if ( tag != SLAP_X509_GN_DIRECTORYNAME ) { 
4806                 return LDAP_INVALID_SYNTAX; 
4807         }
4808         tag = ber_peek_tag( ber, &len );        /* sequence of RDN */
4809         len = ber_ptrlen( ber );
4810         bvdn.bv_val = val->bv_val + len;
4811         bvdn.bv_len = val->bv_len - len;
4812         rc = dnX509normalize( &bvdn, &issuer_dn );
4813         if ( rc != LDAP_SUCCESS ) goto done;
4814         
4815         tag = ber_skip_tag( ber, &len );        /* sequence of RDN */
4816         ber_skip_data( ber, len ); 
4817         tag = ber_skip_tag( ber, &len );        /* serial number */
4818         if ( tag != LBER_INTEGER ) {
4819                 rc = LDAP_INVALID_SYNTAX; 
4820                 goto done;
4821         }
4822         i_sn.bv_val = (char *)ber->ber_ptr;
4823         i_sn.bv_len = len;
4824         i_sn2.bv_val = issuer_serialbuf;
4825         i_sn2.bv_len = sizeof(issuer_serialbuf);
4826         if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) {
4827                 rc = LDAP_INVALID_SYNTAX;
4828                 goto done;
4829         }
4830         ber_skip_data( ber, len );
4831
4832                                                 /* issuerUID (bitstring; optional)? */
4833                                                 /* objectDigestInfo (sequence; optional)? */
4834
4835         tag = ber_skip_tag( ber, &len );        /* Signature (sequence) */
4836         ber_skip_data( ber, len );
4837         tag = ber_skip_tag( ber, &len );        /* serial number */ 
4838         if ( tag != LBER_INTEGER ) {
4839                 rc = LDAP_INVALID_SYNTAX; 
4840                 goto done;
4841         }
4842         sn.bv_val = (char *)ber->ber_ptr;
4843         sn.bv_len = len;
4844         sn2.bv_val = serialbuf;
4845         sn2.bv_len = sizeof(serialbuf);
4846         if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
4847                 rc = LDAP_INVALID_SYNTAX;
4848                 goto done;
4849         }
4850         ber_skip_data( ber, len );
4851
4852         normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }" )
4853                 + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len;
4854         normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4855
4856         p = normalized->bv_val;
4857
4858         p = lutil_strcopy( p, "{ serialNumber " );
4859         p = lutil_strbvcopy( p, &sn2 );
4860         p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4861         p = lutil_strbvcopy( p, &issuer_dn );
4862         p = lutil_strcopy( p, "\" }, serial " );
4863         p = lutil_strbvcopy( p, &i_sn2 );
4864         p = lutil_strcopy( p, " } } }" );
4865
4866         Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n",
4867                 normalized->bv_val, NULL, NULL );
4868
4869         rc = LDAP_SUCCESS;
4870
4871 done:
4872         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4873         if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx );
4874         if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx );
4875
4876         return rc;
4877 }
4878
4879
4880 static int
4881 hexValidate(
4882         Syntax *syntax,
4883         struct berval *in )
4884 {
4885         ber_len_t       i;
4886
4887         assert( in != NULL );
4888         assert( !BER_BVISNULL( in ) );
4889
4890         for ( i = 0; i < in->bv_len; i++ ) {
4891                 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
4892                         return LDAP_INVALID_SYNTAX;
4893                 }
4894         }
4895
4896         return LDAP_SUCCESS;
4897 }
4898
4899 /* Normalize a SID as used inside a CSN:
4900  * three-digit numeric string */
4901 static int
4902 hexNormalize(
4903         slap_mask_t usage,
4904         Syntax *syntax,
4905         MatchingRule *mr,
4906         struct berval *val,
4907         struct berval *normalized,
4908         void *ctx )
4909 {
4910         ber_len_t       i;
4911
4912         assert( val != NULL );
4913         assert( normalized != NULL );
4914
4915         ber_dupbv_x( normalized, val, ctx );
4916
4917         for ( i = 0; i < normalized->bv_len; i++ ) {
4918                 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
4919                         ber_memfree_x( normalized->bv_val, ctx );
4920                         BER_BVZERO( normalized );
4921                         return LDAP_INVALID_SYNTAX;
4922                 }
4923
4924                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
4925         }
4926
4927         return LDAP_SUCCESS;
4928 }
4929
4930 static int
4931 sidValidate (
4932         Syntax *syntax,
4933         struct berval *in )
4934 {
4935         assert( in != NULL );
4936         assert( !BER_BVISNULL( in ) );
4937
4938         if ( in->bv_len != 3 ) {
4939                 return LDAP_INVALID_SYNTAX;
4940         }
4941
4942         return hexValidate( NULL, in );
4943 }
4944
4945 /* Normalize a SID as used inside a CSN:
4946  * three-digit numeric string */
4947 static int
4948 sidNormalize(
4949         slap_mask_t usage,
4950         Syntax *syntax,
4951         MatchingRule *mr,
4952         struct berval *val,
4953         struct berval *normalized,
4954         void *ctx )
4955 {
4956         if ( val->bv_len != 3 ) {
4957                 return LDAP_INVALID_SYNTAX;
4958         }
4959
4960         return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
4961 }
4962
4963 static int
4964 sidPretty(
4965         Syntax *syntax,
4966         struct berval *val,
4967         struct berval *out,
4968         void *ctx )
4969 {
4970         return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
4971 }
4972
4973 /* Normalize a SID as used inside a CSN, either as-is
4974  * (assertion value) or extracted from the CSN
4975  * (attribute value) */
4976 static int
4977 csnSidNormalize(
4978         slap_mask_t usage,
4979         Syntax *syntax,
4980         MatchingRule *mr,
4981         struct berval *val,
4982         struct berval *normalized,
4983         void *ctx )
4984 {
4985         struct berval   bv;
4986         char            *ptr,
4987                         buf[ 4 ];
4988
4989
4990         if ( BER_BVISEMPTY( val ) ) {
4991                 return LDAP_INVALID_SYNTAX;
4992         }
4993
4994         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4995                 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
4996         }
4997
4998         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4999
5000         ptr = ber_bvchr( val, '#' );
5001         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5002                 return LDAP_INVALID_SYNTAX;
5003         }
5004
5005         bv.bv_val = ptr + 1;
5006         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5007
5008         ptr = ber_bvchr( &bv, '#' );
5009         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5010                 return LDAP_INVALID_SYNTAX;
5011         }
5012
5013         bv.bv_val = ptr + 1;
5014         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5015                 
5016         ptr = ber_bvchr( &bv, '#' );
5017         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5018                 return LDAP_INVALID_SYNTAX;
5019         }
5020
5021         bv.bv_len = ptr - bv.bv_val;
5022
5023         if ( bv.bv_len == 2 ) {
5024                 /* OpenLDAP 2.3 SID */
5025                 buf[ 0 ] = '0';
5026                 buf[ 1 ] = bv.bv_val[ 0 ];
5027                 buf[ 2 ] = bv.bv_val[ 1 ];
5028                 buf[ 3 ] = '\0';
5029
5030                 bv.bv_val = buf;
5031                 bv.bv_len = 3;
5032         }
5033
5034         return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
5035 }
5036
5037 static int
5038 csnValidate(
5039         Syntax *syntax,
5040         struct berval *in )
5041 {
5042         struct berval   bv;
5043         char            *ptr;
5044         int             rc;
5045
5046         assert( in != NULL );
5047         assert( !BER_BVISNULL( in ) );
5048
5049         if ( BER_BVISEMPTY( in ) ) {
5050                 return LDAP_INVALID_SYNTAX;
5051         }
5052
5053         bv = *in;
5054
5055         ptr = ber_bvchr( &bv, '#' );
5056         if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) {
5057                 return LDAP_INVALID_SYNTAX;
5058         }
5059
5060         bv.bv_len = ptr - bv.bv_val;
5061         if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
5062                 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
5063         {
5064                 return LDAP_INVALID_SYNTAX;
5065         }
5066
5067         rc = generalizedTimeValidate( NULL, &bv );
5068         if ( rc != LDAP_SUCCESS ) {
5069                 return rc;
5070         }
5071
5072         bv.bv_val = ptr + 1;
5073         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5074
5075         ptr = ber_bvchr( &bv, '#' );
5076         if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5077                 return LDAP_INVALID_SYNTAX;
5078         }
5079
5080         bv.bv_len = ptr - bv.bv_val;
5081         if ( bv.bv_len != 6 ) {
5082                 return LDAP_INVALID_SYNTAX;
5083         }
5084
5085         rc = hexValidate( NULL, &bv );
5086         if ( rc != LDAP_SUCCESS ) {
5087                 return rc;
5088         }
5089
5090         bv.bv_val = ptr + 1;
5091         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5092
5093         ptr = ber_bvchr( &bv, '#' );
5094         if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5095                 return LDAP_INVALID_SYNTAX;
5096         }
5097
5098         bv.bv_len = ptr - bv.bv_val;
5099         if ( bv.bv_len == 2 ) {
5100                 /* tolerate old 2-digit replica-id */
5101                 rc = hexValidate( NULL, &bv );
5102
5103         } else {
5104                 rc = sidValidate( NULL, &bv );
5105         }
5106         if ( rc != LDAP_SUCCESS ) {
5107                 return rc;
5108         }
5109
5110         bv.bv_val = ptr + 1;
5111         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5112
5113         if ( bv.bv_len != 6 ) {
5114                 return LDAP_INVALID_SYNTAX;
5115         }
5116
5117         return hexValidate( NULL, &bv );
5118 }
5119
5120 /* Normalize a CSN in OpenLDAP 2.1 format */
5121 static int
5122 csnNormalize21(
5123         slap_mask_t usage,
5124         Syntax *syntax,
5125         MatchingRule *mr,
5126         struct berval *val,
5127         struct berval *normalized,
5128         void *ctx )
5129 {
5130         struct berval   gt, cnt, sid, mod;
5131         struct berval   bv;
5132         char            buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5133         char            *ptr;
5134         ber_len_t       i;
5135
5136         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5137         assert( !BER_BVISEMPTY( val ) );
5138
5139         gt = *val;
5140
5141         ptr = ber_bvchr( &gt, '#' );
5142         if ( ptr == NULL || ptr == &gt.bv_val[gt.bv_len] ) {
5143                 return LDAP_INVALID_SYNTAX;
5144         }
5145
5146         gt.bv_len = ptr - gt.bv_val;
5147         if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
5148                 return LDAP_INVALID_SYNTAX;
5149         }
5150
5151         if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
5152                 return LDAP_INVALID_SYNTAX;
5153         }
5154
5155         cnt.bv_val = ptr + 1;
5156         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5157
5158         ptr = ber_bvchr( &cnt, '#' );
5159         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5160                 return LDAP_INVALID_SYNTAX;
5161         }
5162
5163         cnt.bv_len = ptr - cnt.bv_val;
5164         if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
5165                 return LDAP_INVALID_SYNTAX;
5166         }
5167
5168         if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
5169                 return LDAP_INVALID_SYNTAX;
5170         }
5171
5172         cnt.bv_val += STRLENOF( "0x" );
5173         cnt.bv_len -= STRLENOF( "0x" );
5174
5175         sid.bv_val = ptr + 1;
5176         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5177                 
5178         ptr = ber_bvchr( &sid, '#' );
5179         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5180                 return LDAP_INVALID_SYNTAX;
5181         }
5182
5183         sid.bv_len = ptr - sid.bv_val;
5184         if ( sid.bv_len != STRLENOF( "0" ) ) {
5185                 return LDAP_INVALID_SYNTAX;
5186         }
5187
5188         mod.bv_val = ptr + 1;
5189         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5190         if ( mod.bv_len != STRLENOF( "0000" ) ) {
5191                 return LDAP_INVALID_SYNTAX;
5192         }
5193
5194         bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5195         bv.bv_val = buf;
5196
5197         ptr = bv.bv_val;
5198         ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
5199         ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
5200                 STRLENOF( "MM" ) );
5201         ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
5202                 STRLENOF( "SS" ) );
5203         ptr = lutil_strcopy( ptr, ".000000Z#00" );
5204         ptr = lutil_strbvcopy( ptr, &cnt );
5205         *ptr++ = '#';
5206         *ptr++ = '0';
5207         *ptr++ = '0';
5208         *ptr++ = sid.bv_val[ 0 ];
5209         *ptr++ = '#';
5210         *ptr++ = '0';
5211         *ptr++ = '0';
5212         for ( i = 0; i < mod.bv_len; i++ ) {
5213                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5214         }
5215         *ptr = '\0';
5216
5217         assert( ptr == &bv.bv_val[bv.bv_len] );
5218
5219         if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5220                 return LDAP_INVALID_SYNTAX;
5221         }
5222
5223         ber_dupbv_x( normalized, &bv, ctx );
5224
5225         return LDAP_SUCCESS;
5226 }
5227
5228 /* Normalize a CSN in OpenLDAP 2.3 format */
5229 static int
5230 csnNormalize23(
5231         slap_mask_t usage,
5232         Syntax *syntax,
5233         MatchingRule *mr,
5234         struct berval *val,
5235         struct berval *normalized,
5236         void *ctx )
5237 {
5238         struct berval   gt, cnt, sid, mod;
5239         struct berval   bv;
5240         char            buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5241         char            *ptr;
5242         ber_len_t       i;
5243
5244         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5245         assert( !BER_BVISEMPTY( val ) );
5246
5247         gt = *val;
5248
5249         ptr = ber_bvchr( &gt, '#' );
5250         if ( ptr == NULL || ptr == &gt.bv_val[gt.bv_len] ) {
5251                 return LDAP_INVALID_SYNTAX;
5252         }
5253
5254         gt.bv_len = ptr - gt.bv_val;
5255         if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
5256                 return LDAP_INVALID_SYNTAX;
5257         }
5258
5259         cnt.bv_val = ptr + 1;
5260         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5261
5262         ptr = ber_bvchr( &cnt, '#' );
5263         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5264                 return LDAP_INVALID_SYNTAX;
5265         }
5266
5267         cnt.bv_len = ptr - cnt.bv_val;
5268         if ( cnt.bv_len != STRLENOF( "000000" ) ) {
5269                 return LDAP_INVALID_SYNTAX;
5270         }
5271
5272         sid.bv_val = ptr + 1;
5273         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5274                 
5275         ptr = ber_bvchr( &sid, '#' );
5276         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5277                 return LDAP_INVALID_SYNTAX;
5278         }
5279
5280         sid.bv_len = ptr - sid.bv_val;
5281         if ( sid.bv_len != STRLENOF( "00" ) ) {
5282                 return LDAP_INVALID_SYNTAX;
5283         }
5284
5285         mod.bv_val = ptr + 1;
5286         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5287         if ( mod.bv_len != STRLENOF( "000000" ) ) {
5288                 return LDAP_INVALID_SYNTAX;
5289         }
5290
5291         bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5292         bv.bv_val = buf;
5293
5294         ptr = bv.bv_val;
5295         ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
5296         ptr = lutil_strcopy( ptr, ".000000Z#" );
5297         ptr = lutil_strbvcopy( ptr, &cnt );
5298         *ptr++ = '#';
5299         *ptr++ = '0';
5300         for ( i = 0; i < sid.bv_len; i++ ) {
5301                 *ptr++ = TOLOWER( sid.bv_val[ i ] );
5302         }
5303         *ptr++ = '#';
5304         for ( i = 0; i < mod.bv_len; i++ ) {
5305                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5306         }
5307         *ptr = '\0';
5308
5309         assert( ptr == &bv.bv_val[bv.bv_len] );
5310         if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5311                 return LDAP_INVALID_SYNTAX;
5312         }
5313
5314         ber_dupbv_x( normalized, &bv, ctx );
5315
5316         return LDAP_SUCCESS;
5317 }
5318
5319 /* Normalize a CSN */
5320 static int
5321 csnNormalize(
5322         slap_mask_t usage,
5323         Syntax *syntax,
5324         MatchingRule *mr,
5325         struct berval *val,
5326         struct berval *normalized,
5327         void *ctx )
5328 {
5329         struct berval   cnt, sid, mod;
5330         char            *ptr;
5331         ber_len_t       i;
5332
5333         assert( val != NULL );
5334         assert( normalized != NULL );
5335
5336         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5337
5338         if ( BER_BVISEMPTY( val ) ) {
5339                 return LDAP_INVALID_SYNTAX;
5340         }
5341
5342         if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
5343                 /* Openldap <= 2.3 */
5344
5345                 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
5346         }
5347
5348         if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
5349                 /* Openldap 2.1 */
5350
5351                 return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
5352         }
5353
5354         if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
5355                 return LDAP_INVALID_SYNTAX;
5356         }
5357
5358         ptr = ber_bvchr( val, '#' );
5359         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5360                 return LDAP_INVALID_SYNTAX;
5361         }
5362
5363         if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
5364                 return LDAP_INVALID_SYNTAX;
5365         }
5366
5367         cnt.bv_val = ptr + 1;
5368         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5369
5370         ptr = ber_bvchr( &cnt, '#' );
5371         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5372                 return LDAP_INVALID_SYNTAX;
5373         }
5374
5375         if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
5376                 return LDAP_INVALID_SYNTAX;
5377         }
5378
5379         sid.bv_val = ptr + 1;
5380         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5381                 
5382         ptr = ber_bvchr( &sid, '#' );
5383         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5384                 return LDAP_INVALID_SYNTAX;
5385         }
5386
5387         sid.bv_len = ptr - sid.bv_val;
5388         if ( sid.bv_len != STRLENOF( "000" ) ) {
5389                 return LDAP_INVALID_SYNTAX;
5390         }
5391
5392         mod.bv_val = ptr + 1;
5393         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5394
5395         if ( mod.bv_len != STRLENOF( "000000" ) ) {
5396                 return LDAP_INVALID_SYNTAX;
5397         }
5398
5399         ber_dupbv_x( normalized, val, ctx );
5400
5401         for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
5402                 i < normalized->bv_len; i++ )
5403         {
5404                 /* assume it's already validated that's all hex digits */
5405                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5406         }
5407
5408         return LDAP_SUCCESS;
5409 }
5410
5411 static int
5412 csnPretty(
5413         Syntax *syntax,
5414         struct berval *val,
5415         struct berval *out,
5416         void *ctx )
5417 {
5418         return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5419 }
5420
5421 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
5422 /* slight optimization - does not need the start parameter */
5423 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
5424 enum { start = 0 };
5425 #endif
5426
5427 static int
5428 check_time_syntax (struct berval *val,
5429         int start,
5430         int *parts,
5431         struct berval *fraction)
5432 {
5433         /*
5434          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
5435          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
5436          * GeneralizedTime supports leap seconds, UTCTime does not.
5437          */
5438         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
5439         static const int mdays[2][12] = {
5440                 /* non-leap years */
5441                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
5442                 /* leap years */
5443                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
5444         };
5445         char *p, *e;
5446         int part, c, c1, c2, tzoffset, leapyear = 0;
5447
5448         p = val->bv_val;
5449         e = p + val->bv_len;
5450
5451 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5452         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
5453 #endif
5454         for (part = start; part < 7 && p < e; part++) {
5455                 c1 = *p;
5456                 if (!ASCII_DIGIT(c1)) {
5457                         break;
5458                 }
5459                 p++;
5460                 if (p == e) {
5461                         return LDAP_INVALID_SYNTAX;
5462                 }
5463                 c = *p++;
5464                 if (!ASCII_DIGIT(c)) {
5465                         return LDAP_INVALID_SYNTAX;
5466                 }
5467                 c += c1 * 10 - '0' * 11;
5468                 if ((part | 1) == 3) {
5469                         --c;
5470                         if (c < 0) {
5471                                 return LDAP_INVALID_SYNTAX;
5472                         }
5473                 }
5474                 if (c >= ceiling[part]) {
5475                         if (! (c == 60 && part == 6 && start == 0))
5476                                 return LDAP_INVALID_SYNTAX;
5477                 }
5478                 parts[part] = c;
5479         }
5480         if (part < 5 + start) {
5481                 return LDAP_INVALID_SYNTAX;
5482         }
5483         for (; part < 9; part++) {
5484                 parts[part] = 0;
5485         }
5486
5487         /* leapyear check for the Gregorian calendar (year>1581) */
5488         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
5489                 leapyear = 1;
5490         }
5491
5492         if (parts[3] >= mdays[leapyear][parts[2]]) {
5493                 return LDAP_INVALID_SYNTAX;
5494         }
5495
5496         if (start == 0) {
5497                 fraction->bv_val = p;
5498                 fraction->bv_len = 0;
5499                 if (p < e && (*p == '.' || *p == ',')) {
5500                         char *end_num;
5501                         while (++p < e && ASCII_DIGIT(*p)) {
5502                                 /* EMTPY */;
5503                         }
5504                         if (p - fraction->bv_val == 1) {
5505                                 return LDAP_INVALID_SYNTAX;
5506                         }
5507                         for (end_num = p; end_num[-1] == '0'; --end_num) {
5508                                 /* EMPTY */;
5509                         }
5510                         c = end_num - fraction->bv_val;
5511                         if (c != 1) fraction->bv_len = c;
5512                 }
5513         }
5514
5515         if (p == e) {
5516                 /* no time zone */
5517                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5518         }
5519
5520         tzoffset = *p++;
5521         switch (tzoffset) {
5522         default:
5523                 return LDAP_INVALID_SYNTAX;
5524         case 'Z':
5525                 /* UTC */
5526                 break;
5527         case '+':
5528         case '-':
5529                 for (part = 7; part < 9 && p < e; part++) {
5530                         c1 = *p;
5531                         if (!ASCII_DIGIT(c1)) {
5532                                 break;
5533                         }
5534                         p++;
5535                         if (p == e) {
5536                                 return LDAP_INVALID_SYNTAX;
5537                         }
5538                         c2 = *p++;
5539                         if (!ASCII_DIGIT(c2)) {
5540                                 return LDAP_INVALID_SYNTAX;
5541                         }
5542                         parts[part] = c1 * 10 + c2 - '0' * 11;
5543                         if (parts[part] >= ceiling[part]) {
5544                                 return LDAP_INVALID_SYNTAX;
5545                         }
5546                 }
5547                 if (part < 8 + start) {
5548                         return LDAP_INVALID_SYNTAX;
5549                 }
5550
5551                 if (tzoffset == '-') {
5552                         /* negative offset to UTC, ie west of Greenwich */
5553                         parts[4] += parts[7];
5554                         parts[5] += parts[8];
5555                         /* offset is just hhmm, no seconds */
5556                         for (part = 6; --part >= 0; ) {
5557                                 if (part != 3) {
5558                                         c = ceiling[part];
5559                                 } else {
5560                                         c = mdays[leapyear][parts[2]];
5561                                 }
5562                                 if (parts[part] >= c) {
5563                                         if (part == 0) {
5564                                                 return LDAP_INVALID_SYNTAX;
5565                                         }
5566                                         parts[part] -= c;
5567                                         parts[part - 1]++;
5568                                         continue;
5569                                 } else if (part != 5) {
5570                                         break;
5571                                 }
5572                         }
5573                 } else {
5574                         /* positive offset to UTC, ie east of Greenwich */
5575                         parts[4] -= parts[7];
5576                         parts[5] -= parts[8];
5577                         for (part = 6; --part >= 0; ) {
5578                                 if (parts[part] < 0) {
5579                                         if (part == 0) {
5580                                                 return LDAP_INVALID_SYNTAX;
5581                                         }
5582                                         if (part != 3) {
5583                                                 c = ceiling[part];
5584                                         } else {
5585                                                 /* make first arg to % non-negative */
5586                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
5587                                         }
5588                                         parts[part] += c;
5589                                         parts[part - 1]--;
5590                                         continue;
5591                                 } else if (part != 5) {
5592                                         break;
5593                                 }
5594                         }
5595                 }
5596         }
5597
5598         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5599 }
5600
5601 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5602
5603 #if 0
5604 static int
5605 xutcTimeNormalize(
5606         Syntax *syntax,
5607         struct berval *val,
5608         struct berval *normalized )
5609 {
5610         int parts[9], rc;
5611
5612         rc = check_time_syntax(val, 1, parts, NULL);
5613         if (rc != LDAP_SUCCESS) {
5614                 return rc;
5615         }
5616
5617         normalized->bv_val = ch_malloc( 14 );
5618         if ( normalized->bv_val == NULL ) {
5619                 return LBER_ERROR_MEMORY;
5620         }
5621
5622         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
5623                 parts[1], parts[2] + 1, parts[3] + 1,
5624                 parts[4], parts[5], parts[6] );
5625         normalized->bv_len = 13;
5626
5627         return LDAP_SUCCESS;
5628 }
5629 #endif /* 0 */
5630
5631 static int
5632 utcTimeValidate(
5633         Syntax *syntax,
5634         struct berval *in )
5635 {
5636         int parts[9];
5637         return check_time_syntax(in, 1, parts, NULL);
5638 }
5639
5640 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
5641
5642 static int
5643 generalizedTimeValidate(
5644         Syntax *syntax,
5645         struct berval *in )
5646 {
5647         int parts[9];
5648         struct berval fraction;
5649         return check_time_syntax(in, 0, parts, &fraction);
5650 }
5651
5652 static int
5653 generalizedTimeNormalize(
5654         slap_mask_t usage,
5655         Syntax *syntax,
5656         MatchingRule *mr,
5657         struct berval *val,
5658         struct berval *normalized,
5659         void *ctx )
5660 {
5661         int parts[9], rc;
5662         unsigned int len;
5663         struct berval fraction;
5664
5665         rc = check_time_syntax(val, 0, parts, &fraction);
5666         if (rc != LDAP_SUCCESS) {
5667                 return rc;
5668         }
5669
5670         len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
5671         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
5672         if ( BER_BVISNULL( normalized ) ) {
5673                 return LBER_ERROR_MEMORY;
5674         }
5675
5676         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
5677                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
5678                 parts[4], parts[5], parts[6] );
5679         if ( !BER_BVISEMPTY( &fraction ) ) {
5680                 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
5681                         fraction.bv_val, fraction.bv_len );
5682                 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
5683         }
5684         strcpy( normalized->bv_val + len-1, "Z" );
5685         normalized->bv_len = len;
5686
5687         return LDAP_SUCCESS;
5688 }
5689
5690 static int
5691 generalizedTimeOrderingMatch(
5692         int *matchp,
5693         slap_mask_t flags,
5694         Syntax *syntax,
5695         MatchingRule *mr,
5696         struct berval *value,
5697         void *assertedValue )
5698 {
5699         struct berval *asserted = (struct berval *) assertedValue;
5700         ber_len_t v_len  = value->bv_len;
5701         ber_len_t av_len = asserted->bv_len;
5702
5703         /* ignore trailing 'Z' when comparing */
5704         int match = memcmp( value->bv_val, asserted->bv_val,
5705                 (v_len < av_len ? v_len : av_len) - 1 );
5706         if ( match == 0 ) match = v_len - av_len;
5707
5708         /* If used in extensible match filter, match if value < asserted */
5709         if ( flags & SLAP_MR_EXT )
5710                 match = (match >= 0);
5711
5712         *matchp = match;
5713         return LDAP_SUCCESS;
5714 }
5715
5716 /* Index generation function: Ordered index */
5717 int generalizedTimeIndexer(
5718         slap_mask_t use,
5719         slap_mask_t flags,
5720         Syntax *syntax,
5721         MatchingRule *mr,
5722         struct berval *prefix,
5723         BerVarray values,
5724         BerVarray *keysp,
5725         void *ctx )
5726 {
5727         int i, j;
5728         BerVarray keys;
5729         char tmp[5];
5730         BerValue bvtmp; /* 40 bit index */
5731         struct lutil_tm tm;
5732         struct lutil_timet tt;
5733
5734         bvtmp.bv_len = sizeof(tmp);
5735         bvtmp.bv_val = tmp;
5736         for( i=0; values[i].bv_val != NULL; i++ ) {
5737                 /* just count them */
5738         }
5739
5740         /* we should have at least one value at this point */
5741         assert( i > 0 );
5742
5743         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
5744
5745         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5746         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
5747                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
5748                 /* Use 40 bits of time for key */
5749                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
5750                         lutil_tm2time( &tm, &tt );
5751                         tmp[0] = tt.tt_gsec & 0xff;
5752                         tmp[4] = tt.tt_sec & 0xff;
5753                         tt.tt_sec >>= 8;
5754                         tmp[3] = tt.tt_sec & 0xff;
5755                         tt.tt_sec >>= 8;
5756                         tmp[2] = tt.tt_sec & 0xff;
5757                         tt.tt_sec >>= 8;
5758                         tmp[1] = tt.tt_sec & 0xff;
5759                         
5760                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
5761                 }
5762         }
5763
5764         keys[j].bv_val = NULL;
5765         keys[j].bv_len = 0;
5766
5767         *keysp = keys;
5768
5769         return LDAP_SUCCESS;
5770 }
5771
5772 /* Index generation function: Ordered index */
5773 int generalizedTimeFilter(
5774         slap_mask_t use,
5775         slap_mask_t flags,
5776         Syntax *syntax,
5777         MatchingRule *mr,
5778         struct berval *prefix,
5779         void * assertedValue,
5780         BerVarray *keysp,
5781         void *ctx )
5782 {
5783         BerVarray keys;
5784         char tmp[5];
5785         BerValue bvtmp; /* 40 bit index */
5786         BerValue *value = (BerValue *) assertedValue;
5787         struct lutil_tm tm;
5788         struct lutil_timet tt;
5789         
5790         bvtmp.bv_len = sizeof(tmp);
5791         bvtmp.bv_val = tmp;
5792         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5793         /* Use 40 bits of time for key */
5794         if ( value->bv_val && value->bv_len >= 10 &&
5795                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
5796
5797                 lutil_tm2time( &tm, &tt );
5798                 tmp[0] = tt.tt_gsec & 0xff;
5799                 tmp[4] = tt.tt_sec & 0xff;
5800                 tt.tt_sec >>= 8;
5801                 tmp[3] = tt.tt_sec & 0xff;
5802                 tt.tt_sec >>= 8;
5803                 tmp[2] = tt.tt_sec & 0xff;
5804                 tt.tt_sec >>= 8;
5805                 tmp[1] = tt.tt_sec & 0xff;
5806
5807                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
5808                 ber_dupbv_x(keys, &bvtmp, ctx );
5809                 keys[1].bv_val = NULL;
5810                 keys[1].bv_len = 0;
5811         } else {
5812                 keys = NULL;
5813         }
5814
5815         *keysp = keys;
5816
5817         return LDAP_SUCCESS;
5818 }
5819
5820 static int
5821 deliveryMethodValidate(
5822         Syntax *syntax,
5823         struct berval *val )
5824 {
5825 #undef LENOF
5826 #define LENOF(s) (sizeof(s)-1)
5827         struct berval tmp = *val;
5828         /*
5829      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
5830          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
5831          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
5832          */
5833 again:
5834         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5835
5836         switch( tmp.bv_val[0] ) {
5837         case 'a':
5838         case 'A':
5839                 if(( tmp.bv_len >= LENOF("any") ) &&
5840                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
5841                 {
5842                         tmp.bv_len -= LENOF("any");
5843                         tmp.bv_val += LENOF("any");
5844                         break;
5845                 }
5846                 return LDAP_INVALID_SYNTAX;
5847
5848         case 'm':
5849         case 'M':
5850                 if(( tmp.bv_len >= LENOF("mhs") ) &&
5851                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
5852                 {
5853                         tmp.bv_len -= LENOF("mhs");
5854                         tmp.bv_val += LENOF("mhs");
5855                         break;
5856                 }
5857                 return LDAP_INVALID_SYNTAX;
5858
5859         case 'p':
5860         case 'P':
5861                 if(( tmp.bv_len >= LENOF("physical") ) &&
5862                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
5863                 {
5864                         tmp.bv_len -= LENOF("physical");
5865                         tmp.bv_val += LENOF("physical");
5866                         break;
5867                 }
5868                 return LDAP_INVALID_SYNTAX;
5869
5870         case 't':
5871         case 'T': /* telex or teletex or telephone */
5872                 if(( tmp.bv_len >= LENOF("telex") ) &&
5873                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
5874                 {
5875                         tmp.bv_len -= LENOF("telex");
5876                         tmp.bv_val += LENOF("telex");
5877                         break;
5878                 }
5879                 if(( tmp.bv_len >= LENOF("teletex") ) &&
5880                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
5881                 {
5882                         tmp.bv_len -= LENOF("teletex");
5883                         tmp.bv_val += LENOF("teletex");
5884                         break;
5885                 }
5886                 if(( tmp.bv_len >= LENOF("telephone") ) &&
5887                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
5888                 {
5889                         tmp.bv_len -= LENOF("telephone");
5890                         tmp.bv_val += LENOF("telephone");
5891                         break;
5892                 }
5893                 return LDAP_INVALID_SYNTAX;
5894
5895         case 'g':
5896         case 'G': /* g3fax or g4fax */
5897                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
5898                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
5899                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
5900                 {
5901                         tmp.bv_len -= LENOF("g3fax");
5902                         tmp.bv_val += LENOF("g3fax");
5903                         break;
5904                 }
5905                 return LDAP_INVALID_SYNTAX;
5906
5907         case 'i':
5908         case 'I':
5909                 if(( tmp.bv_len >= LENOF("ia5") ) &&
5910                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
5911                 {
5912                         tmp.bv_len -= LENOF("ia5");
5913                         tmp.bv_val += LENOF("ia5");
5914                         break;
5915                 }
5916                 return LDAP_INVALID_SYNTAX;
5917
5918         case 'v':
5919         case 'V':
5920                 if(( tmp.bv_len >= LENOF("videotex") ) &&
5921                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
5922                 {
5923                         tmp.bv_len -= LENOF("videotex");
5924                         tmp.bv_val += LENOF("videotex");
5925                         break;
5926                 }
5927                 return LDAP_INVALID_SYNTAX;
5928
5929         default:
5930                 return LDAP_INVALID_SYNTAX;
5931         }
5932
5933         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
5934
5935         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5936                 tmp.bv_len++;
5937                 tmp.bv_val--;
5938         }
5939         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
5940                 tmp.bv_len++;
5941                 tmp.bv_val--;
5942         } else {
5943                 return LDAP_INVALID_SYNTAX;
5944         }
5945         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5946                 tmp.bv_len++;
5947                 tmp.bv_val--;
5948         }
5949
5950         goto again;
5951 }
5952
5953 static int
5954 nisNetgroupTripleValidate(
5955         Syntax *syntax,
5956         struct berval *val )
5957 {
5958         char *p, *e;
5959         int commas = 0;
5960
5961         if ( BER_BVISEMPTY( val ) ) {
5962                 return LDAP_INVALID_SYNTAX;
5963         }
5964
5965         p = (char *)val->bv_val;
5966         e = p + val->bv_len;
5967
5968         if ( *p != '(' /*')'*/ ) {
5969                 return LDAP_INVALID_SYNTAX;
5970         }
5971
5972         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
5973                 if ( *p == ',' ) {
5974                         commas++;
5975                         if ( commas > 2 ) {
5976                                 return LDAP_INVALID_SYNTAX;
5977                         }
5978
5979                 } else if ( !AD_CHAR( *p ) ) {
5980                         return LDAP_INVALID_SYNTAX;
5981                 }
5982         }
5983
5984         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
5985                 return LDAP_INVALID_SYNTAX;
5986         }
5987
5988         p++;
5989
5990         if (p != e) {
5991                 return LDAP_INVALID_SYNTAX;
5992         }
5993
5994         return LDAP_SUCCESS;
5995 }
5996
5997 static int
5998 bootParameterValidate(
5999         Syntax *syntax,
6000         struct berval *val )
6001 {
6002         char *p, *e;
6003
6004         if ( BER_BVISEMPTY( val ) ) {
6005                 return LDAP_INVALID_SYNTAX;
6006         }
6007
6008         p = (char *)val->bv_val;
6009         e = p + val->bv_len;
6010
6011         /* key */
6012         for (; ( p < e ) && ( *p != '=' ); p++ ) {
6013                 if ( !AD_CHAR( *p ) ) {
6014                         return LDAP_INVALID_SYNTAX;
6015                 }
6016         }
6017
6018         if ( *p != '=' ) {
6019                 return LDAP_INVALID_SYNTAX;
6020         }
6021
6022         /* server */
6023         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
6024                 if ( !AD_CHAR( *p ) ) {
6025                         return LDAP_INVALID_SYNTAX;
6026                 }
6027         }
6028
6029         if ( *p != ':' ) {
6030                 return LDAP_INVALID_SYNTAX;
6031         }
6032
6033         /* path */
6034         for ( p++; p < e; p++ ) {
6035                 if ( !SLAP_PRINTABLE( *p ) ) {
6036                         return LDAP_INVALID_SYNTAX;
6037                 }
6038         }
6039
6040         return LDAP_SUCCESS;
6041 }
6042
6043 static int
6044 firstComponentNormalize(
6045         slap_mask_t usage,
6046         Syntax *syntax,
6047         MatchingRule *mr,
6048         struct berval *val,
6049         struct berval *normalized,
6050         void *ctx )
6051 {
6052         int rc;
6053         struct berval comp;
6054         ber_len_t len;
6055
6056         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
6057                 ber_dupbv_x( normalized, val, ctx );
6058                 return LDAP_SUCCESS;
6059         }
6060
6061         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
6062
6063         if( ! ( val->bv_val[0] == '(' /*')'*/
6064                         && val->bv_val[val->bv_len - 1] == /*'('*/ ')' )
6065                 && ! ( val->bv_val[0] == '{' /*'}'*/
6066                         && val->bv_val[val->bv_len - 1] == /*'('*/ '}' ) )
6067         {
6068                 return LDAP_INVALID_SYNTAX;
6069         }
6070
6071         /* trim leading white space */
6072         for( len=1;
6073                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
6074                 len++ )
6075         {
6076                 /* empty */
6077         }
6078
6079         /* grab next word */
6080         comp.bv_val = &val->bv_val[len];
6081         len = val->bv_len - len - STRLENOF(/*"{"*/ "}");
6082         for( comp.bv_len = 0;
6083                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
6084                 comp.bv_len++ )
6085         {
6086                 /* empty */
6087         }
6088
6089         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
6090                 rc = numericoidValidate( NULL, &comp );
6091         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
6092                 rc = integerValidate( NULL, &comp );
6093         } else {
6094                 rc = LDAP_INVALID_SYNTAX;
6095         }
6096         
6097
6098         if( rc == LDAP_SUCCESS ) {
6099                 ber_dupbv_x( normalized, &comp, ctx );
6100         }
6101
6102         return rc;
6103 }
6104
6105 static char *country_gen_syn[] = {
6106         "1.3.6.1.4.1.1466.115.121.1.15",        /* Directory String */
6107         "1.3.6.1.4.1.1466.115.121.1.26",        /* IA5 String */
6108         "1.3.6.1.4.1.1466.115.121.1.44",        /* Printable String */
6109         NULL
6110 };
6111
6112 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
6113 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
6114
6115 static slap_syntax_defs_rec syntax_defs[] = {
6116         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
6117                 X_BINARY X_NOT_H_R ")",
6118                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
6119         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
6120                 0, NULL, NULL, NULL},
6121         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
6122                 0, NULL, NULL, NULL},
6123         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
6124                 X_NOT_H_R ")",
6125                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6126         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
6127                 X_NOT_H_R ")",
6128                 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6129         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
6130                 0, NULL, bitStringValidate, NULL },
6131         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
6132                 0, NULL, booleanValidate, NULL},
6133         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
6134                 X_BINARY X_NOT_H_R ")",
6135                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6136                 NULL, certificateValidate, NULL},
6137         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
6138                 X_BINARY X_NOT_H_R ")",
6139                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6140                 NULL, certificateListValidate, NULL},
6141         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
6142                 X_BINARY X_NOT_H_R ")",
6143                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6144                 NULL, sequenceValidate, NULL},
6145         {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' "
6146                 X_BINARY X_NOT_H_R ")",
6147                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6148                 NULL, attributeCertificateValidate, NULL},
6149 #if 0   /* need to go __after__ printableString */
6150         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6151                 0, "1.3.6.1.4.1.1466.115.121.1.44",
6152                 countryStringValidate, NULL},
6153 #endif
6154         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
6155                 SLAP_SYNTAX_DN, NULL, dnValidate, dnPretty},
6156         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
6157                 0, NULL, rdnValidate, rdnPretty},
6158 #ifdef LDAP_COMP_MATCH
6159         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
6160                 0, NULL, allComponentsValidate, NULL},
6161         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
6162                 0, NULL, componentFilterValidate, NULL},
6163 #endif
6164         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
6165                 0, NULL, NULL, NULL},
6166         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
6167                 0, NULL, deliveryMethodValidate, NULL},
6168         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
6169                 0, NULL, UTF8StringValidate, NULL},
6170         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
6171                 0, NULL, NULL, NULL},
6172         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
6173                 0, NULL, NULL, NULL},
6174         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
6175                 0, NULL, NULL, NULL},
6176         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
6177                 0, NULL, NULL, NULL},
6178         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
6179                 0, NULL, NULL, NULL},
6180         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
6181                 0, NULL, printablesStringValidate, NULL},
6182         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
6183                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
6184         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
6185                 0, NULL, generalizedTimeValidate, NULL},
6186         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
6187                 0, NULL, NULL, NULL},
6188         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
6189                 0, NULL, IA5StringValidate, NULL},
6190         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
6191                 0, NULL, integerValidate, NULL},
6192         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
6193                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6194         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
6195                 0, NULL, NULL, NULL},
6196         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
6197                 0, NULL, NULL, NULL},
6198         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
6199                 0, NULL, NULL, NULL},
6200         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
6201                 0, NULL, NULL, NULL},
6202         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
6203                 0, NULL, NULL, NULL},
6204         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
6205                 SLAP_SYNTAX_DN, NULL, nameUIDValidate, nameUIDPretty },
6206         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
6207                 0, NULL, NULL, NULL},
6208         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
6209                 0, NULL, numericStringValidate, NULL},
6210         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
6211                 0, NULL, NULL, NULL},
6212         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
6213                 0, NULL, numericoidValidate, NULL},
6214         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
6215                 0, NULL, IA5StringValidate, NULL},
6216         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
6217                 0, NULL, blobValidate, NULL},
6218         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
6219                 0, NULL, postalAddressValidate, NULL},
6220         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
6221                 0, NULL, NULL, NULL},
6222         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
6223                 0, NULL, NULL, NULL},
6224         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
6225                 0, NULL, printableStringValidate, NULL},
6226         /* moved here because now depends on Directory String, IA5 String 
6227          * and Printable String */
6228         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6229                 0, country_gen_syn, countryStringValidate, NULL},
6230         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
6231 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
6232                 0, NULL, subtreeSpecificationValidate, NULL},
6233         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
6234                 X_BINARY X_NOT_H_R ")",
6235                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6236         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
6237                 0, NULL, printableStringValidate, NULL},
6238         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
6239                 0, NULL, NULL, NULL},
6240         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
6241                 0, NULL, printablesStringValidate, NULL},
6242 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
6243         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
6244                 0, NULL, utcTimeValidate, NULL},
6245 #endif
6246         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
6247                 0, NULL, NULL, NULL},
6248         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
6249                 0, NULL, NULL, NULL},
6250         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
6251                 0, NULL, NULL, NULL},
6252         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
6253                 0, NULL, NULL, NULL},
6254         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
6255                 0, NULL, NULL, NULL},
6256
6257         /* RFC 2307 NIS Syntaxes */
6258         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
6259                 0, NULL, nisNetgroupTripleValidate, NULL},
6260         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
6261                 0, NULL, bootParameterValidate, NULL},
6262
6263         /* draft-zeilenga-ldap-x509 */
6264         {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
6265                 SLAP_SYNTAX_HIDE, NULL,
6266                 serialNumberAndIssuerValidate,
6267                 serialNumberAndIssuerPretty},
6268         {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
6269                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6270         {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
6271                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6272         {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
6273                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6274         {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
6275                 SLAP_SYNTAX_HIDE, NULL,
6276                 issuerAndThisUpdateValidate,
6277                 issuerAndThisUpdatePretty},
6278         {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
6279                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6280         {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
6281                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6282         {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )",
6283                 SLAP_SYNTAX_HIDE, NULL,
6284                 serialNumberAndIssuerSerialValidate,
6285                 serialNumberAndIssuerSerialPretty},
6286         {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )",
6287                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6288
6289 #ifdef SLAPD_AUTHPASSWD
6290         /* needs updating */
6291         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
6292                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6293 #endif
6294
6295         {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
6296                 0, NULL, UUIDValidate, UUIDPretty},
6297
6298         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
6299                 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
6300
6301         {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
6302                 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
6303
6304         /* OpenLDAP Void Syntax */
6305         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
6306                 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
6307
6308         /* FIXME: OID is unused, but not registered yet */
6309         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
6310                 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
6311
6312         {NULL, 0, NULL, NULL, NULL}
6313 };
6314
6315 char *csnSIDMatchSyntaxes[] = {
6316         "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
6317         NULL
6318 };
6319 char *certificateExactMatchSyntaxes[] = {
6320         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6321         NULL
6322 };
6323 char *certificateListExactMatchSyntaxes[] = {
6324         "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6325         NULL
6326 };
6327 char *attributeCertificateExactMatchSyntaxes[] = {
6328         attributeCertificateSyntaxOID  /* attributeCertificate */,
6329         NULL
6330 };
6331
6332 #ifdef LDAP_COMP_MATCH
6333 char *componentFilterMatchSyntaxes[] = {
6334         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6335         "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6336         attributeCertificateSyntaxOID /* attributeCertificate */,
6337         NULL
6338 };
6339 #endif
6340
6341 char *directoryStringSyntaxes[] = {
6342         "1.3.6.1.4.1.1466.115.121.1.11" /* countryString */,
6343         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
6344         "1.3.6.1.4.1.1466.115.121.1.50" /* telephoneNumber */,
6345         NULL
6346 };
6347 char *integerFirstComponentMatchSyntaxes[] = {
6348         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
6349         "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
6350         NULL
6351 };
6352 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
6353         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
6354         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
6355         "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
6356         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
6357         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
6358         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
6359         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
6360         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
6361         NULL
6362 };
6363
6364 /*
6365  * Other matching rules in X.520 that we do not use (yet):
6366  *
6367  * 2.5.13.25    uTCTimeMatch
6368  * 2.5.13.26    uTCTimeOrderingMatch
6369  * 2.5.13.31*   directoryStringFirstComponentMatch
6370  * 2.5.13.32*   wordMatch
6371  * 2.5.13.33*   keywordMatch
6372  * 2.5.13.36+   certificatePairExactMatch
6373  * 2.5.13.37+   certificatePairMatch
6374  * 2.5.13.40+   algorithmIdentifierMatch
6375  * 2.5.13.41*   storedPrefixMatch
6376  * 2.5.13.42    attributeCertificateMatch
6377  * 2.5.13.43    readerAndKeyIDMatch
6378  * 2.5.13.44    attributeIntegrityMatch
6379  *
6380  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
6381  * (+) described in draft-zeilenga-ldap-x509
6382  */
6383 static slap_mrule_defs_rec mrule_defs[] = {
6384         /*
6385          * EQUALITY matching rules must be listed after associated APPROX
6386          * matching rules.  So, we list all APPROX matching rules first.
6387          */
6388         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
6389                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6390                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6391                 NULL, NULL, directoryStringApproxMatch,
6392                 directoryStringApproxIndexer, directoryStringApproxFilter,
6393                 NULL},
6394
6395         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
6396                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6397                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6398                 NULL, NULL, IA5StringApproxMatch,
6399                 IA5StringApproxIndexer, IA5StringApproxFilter,
6400                 NULL},
6401
6402         /*
6403          * Other matching rules
6404          */
6405         
6406         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
6407                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
6408                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6409                 NULL, NULL, octetStringMatch,
6410                 octetStringIndexer, octetStringFilter,
6411                 NULL },
6412
6413         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
6414                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6415                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6416                 NULL, dnNormalize, dnMatch,
6417                 octetStringIndexer, octetStringFilter,
6418                 NULL },
6419
6420         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
6421                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6422                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6423                 NULL, dnNormalize, dnRelativeMatch,
6424                 NULL, NULL,
6425                 NULL },
6426
6427         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
6428                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6429                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6430                 NULL, dnNormalize, dnRelativeMatch,
6431                 NULL, NULL,
6432                 NULL },
6433
6434         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
6435                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6436                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6437                 NULL, dnNormalize, dnRelativeMatch,
6438                 NULL, NULL,
6439                 NULL },
6440
6441         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
6442                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6443                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6444                 NULL, dnNormalize, dnRelativeMatch,
6445                 NULL, NULL,
6446                 NULL },
6447
6448         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
6449                 "SYNTAX 1.2.36.79672281.1.5.0 )",
6450                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6451                 NULL, rdnNormalize, rdnMatch,
6452                 octetStringIndexer, octetStringFilter,
6453                 NULL },
6454
6455 #ifdef LDAP_COMP_MATCH
6456         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
6457                 "SYNTAX 1.2.36.79672281.1.5.2 )", /* componentFilterMatch assertion */
6458                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
6459                 NULL, NULL , componentFilterMatch,
6460                 octetStringIndexer, octetStringFilter,
6461                 NULL },
6462
6463         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
6464                 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6465                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6466                 NULL, NULL , allComponentsMatch,
6467                 octetStringIndexer, octetStringFilter,
6468                 NULL },
6469
6470         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
6471                 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6472                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6473                 NULL, NULL , directoryComponentsMatch,
6474                 octetStringIndexer, octetStringFilter,
6475                 NULL },
6476 #endif
6477
6478         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
6479                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6480                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6481                 NULL, UTF8StringNormalize, octetStringMatch,
6482                 octetStringIndexer, octetStringFilter,
6483                 directoryStringApproxMatchOID },
6484
6485         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
6486                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6487                 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6488                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6489                 NULL, NULL,
6490                 "caseIgnoreMatch" },
6491
6492         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
6493                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6494                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6495                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6496                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6497                 "caseIgnoreMatch" },
6498
6499         {"( 2.5.13.5 NAME 'caseExactMatch' "
6500                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6501                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6502                 NULL, UTF8StringNormalize, octetStringMatch,
6503                 octetStringIndexer, octetStringFilter,
6504                 directoryStringApproxMatchOID },
6505
6506         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
6507                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6508                 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6509                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6510                 NULL, NULL,
6511                 "caseExactMatch" },
6512
6513         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
6514                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6515                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6516                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6517                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6518                 "caseExactMatch" },
6519
6520         {"( 2.5.13.8 NAME 'numericStringMatch' "
6521                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6522                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6523                 NULL, numericStringNormalize, octetStringMatch,
6524                 octetStringIndexer, octetStringFilter,
6525                 NULL },
6526
6527         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
6528                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6529                 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6530                 NULL, numericStringNormalize, octetStringOrderingMatch,
6531                 NULL, NULL,
6532                 "numericStringMatch" },
6533
6534         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
6535                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6536                 SLAP_MR_SUBSTR, NULL,
6537                 NULL, numericStringNormalize, octetStringSubstringsMatch,
6538                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6539                 "numericStringMatch" },
6540
6541         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
6542                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", /* Postal Address */
6543                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6544                 NULL, postalAddressNormalize, octetStringMatch,
6545                 octetStringIndexer, octetStringFilter,
6546                 NULL },
6547
6548         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
6549                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6550                 SLAP_MR_SUBSTR, NULL,
6551                 NULL, NULL, NULL, NULL, NULL,
6552                 "caseIgnoreListMatch" },
6553
6554         {"( 2.5.13.13 NAME 'booleanMatch' "
6555                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
6556                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6557                 NULL, NULL, booleanMatch,
6558                 octetStringIndexer, octetStringFilter,
6559                 NULL },
6560
6561         {"( 2.5.13.14 NAME 'integerMatch' "
6562                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6563                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6564                 NULL, NULL, integerMatch,
6565                 integerIndexer, integerFilter,
6566                 NULL },
6567
6568         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
6569                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6570                 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6571                 NULL, NULL, integerMatch,
6572                 NULL, NULL,
6573                 "integerMatch" },
6574
6575         {"( 2.5.13.16 NAME 'bitStringMatch' "
6576                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
6577                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6578                 NULL, NULL, octetStringMatch,
6579                 octetStringIndexer, octetStringFilter,
6580                 NULL },
6581
6582         {"( 2.5.13.17 NAME 'octetStringMatch' "
6583                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6584                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6585                 NULL, NULL, octetStringMatch,
6586                 octetStringIndexer, octetStringFilter,
6587                 NULL },
6588
6589         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
6590                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6591                 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6592                 NULL, NULL, octetStringOrderingMatch,
6593                 NULL, NULL,
6594                 "octetStringMatch" },
6595
6596         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
6597                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6598                 SLAP_MR_SUBSTR, NULL,
6599                 NULL, NULL, octetStringSubstringsMatch,
6600                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6601                 "octetStringMatch" },
6602
6603         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
6604                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
6605                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6606                 NULL,
6607                 telephoneNumberNormalize, octetStringMatch,
6608                 octetStringIndexer, octetStringFilter,
6609                 NULL },
6610
6611         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
6612                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6613                 SLAP_MR_SUBSTR, NULL,
6614                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
6615                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6616                 "telephoneNumberMatch" },
6617
6618         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
6619                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
6620                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6621                 NULL, NULL, NULL, NULL, NULL, NULL },
6622
6623         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
6624                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", /* Name And Optional UID */
6625                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6626                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
6627                 uniqueMemberIndexer, uniqueMemberFilter,
6628                 NULL },
6629
6630         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
6631                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
6632                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6633                 NULL, NULL, NULL, NULL, NULL, NULL },
6634
6635         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
6636                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6637                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6638                 NULL, generalizedTimeNormalize, octetStringMatch,
6639                 generalizedTimeIndexer, generalizedTimeFilter,
6640                 NULL },
6641
6642         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
6643                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6644                 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6645                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
6646                 NULL, NULL,
6647                 "generalizedTimeMatch" },
6648
6649         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
6650                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6651                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6652                         integerFirstComponentMatchSyntaxes,
6653                 NULL, firstComponentNormalize, integerMatch,
6654                 octetStringIndexer, octetStringFilter,
6655                 NULL },
6656
6657         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
6658                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", /* OID */
6659                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6660                         objectIdentifierFirstComponentMatchSyntaxes,
6661                 NULL, firstComponentNormalize, octetStringMatch,
6662                 octetStringIndexer, octetStringFilter,
6663                 NULL },
6664
6665         {"( 2.5.13.34 NAME 'certificateExactMatch' "
6666                 "SYNTAX 1.3.6.1.1.15.1 )", /* Certificate Exact Assertion */
6667                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
6668                 NULL, certificateExactNormalize, octetStringMatch,
6669                 octetStringIndexer, octetStringFilter,
6670                 NULL },
6671
6672         {"( 2.5.13.35 NAME 'certificateMatch' "
6673                 "SYNTAX 1.3.6.1.1.15.2 )", /* Certificate Assertion */
6674                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6675                 NULL, NULL, NULL, NULL, NULL,
6676                 NULL },
6677
6678         {"( 2.5.13.38 NAME 'certificateListExactMatch' "
6679                 "SYNTAX 1.3.6.1.1.15.5 )", /* Certificate List Exact Assertion */
6680                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes,
6681                 NULL, certificateListExactNormalize, octetStringMatch,
6682                 octetStringIndexer, octetStringFilter,
6683                 NULL },
6684
6685         {"( 2.5.13.39 NAME 'certificateListMatch' "
6686                 "SYNTAX 1.3.6.1.1.15.6 )", /* Certificate List Assertion */
6687                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6688                 NULL, NULL, NULL, NULL, NULL,
6689                 NULL },
6690
6691         {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' "
6692                 "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )",
6693                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes,
6694                 NULL, attributeCertificateExactNormalize, octetStringMatch,
6695                 octetStringIndexer, octetStringFilter,
6696                 NULL },
6697
6698         {"( 2.5.13.46 NAME 'attributeCertificateMatch' "
6699                 "SYNTAX " attributeCertificateAssertionSyntaxOID " )",
6700                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL,
6701                 NULL, NULL, NULL, NULL, NULL,
6702                 NULL },
6703
6704         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
6705                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6706                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6707                 NULL, IA5StringNormalize, octetStringMatch,
6708                 octetStringIndexer, octetStringFilter,
6709                 IA5StringApproxMatchOID },
6710
6711         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
6712                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6713                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6714                 NULL, IA5StringNormalize, octetStringMatch,
6715                 octetStringIndexer, octetStringFilter,
6716                 IA5StringApproxMatchOID },
6717
6718         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
6719                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6720                 SLAP_MR_SUBSTR, NULL,
6721                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6722                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6723                 "caseIgnoreIA5Match" },
6724
6725         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
6726                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6727                 SLAP_MR_SUBSTR, NULL,
6728                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6729                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6730                 "caseExactIA5Match" },
6731
6732 #ifdef SLAPD_AUTHPASSWD
6733         /* needs updating */
6734         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
6735                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", /* Octet String */
6736                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6737                 NULL, NULL, authPasswordMatch,
6738                 NULL, NULL,
6739                 NULL},
6740 #endif
6741
6742         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
6743                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6744                 SLAP_MR_EXT, NULL,
6745                 NULL, NULL, integerBitAndMatch,
6746                 NULL, NULL,
6747                 "integerMatch" },
6748
6749         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
6750                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6751                 SLAP_MR_EXT, NULL,
6752                 NULL, NULL, integerBitOrMatch,
6753                 NULL, NULL,
6754                 "integerMatch" },
6755
6756         {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
6757                 "SYNTAX 1.3.6.1.1.16.1 )",
6758                 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
6759                 NULL, UUIDNormalize, octetStringMatch,
6760                 octetStringIndexer, octetStringFilter,
6761                 NULL},
6762
6763         {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
6764                 "SYNTAX 1.3.6.1.1.16.1 )",
6765                 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
6766                 NULL, UUIDNormalize, octetStringOrderingMatch,
6767                 octetStringIndexer, octetStringFilter,
6768                 "UUIDMatch"},
6769
6770         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
6771                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6772                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
6773                 NULL, csnNormalize, csnMatch,
6774                 csnIndexer, csnFilter,
6775                 NULL},
6776
6777         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
6778                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6779                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6780                 NULL, csnNormalize, csnOrderingMatch,
6781                 NULL, NULL,
6782                 "CSNMatch" },
6783
6784         {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
6785                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
6786                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
6787                 NULL, csnSidNormalize, octetStringMatch,
6788                 octetStringIndexer, octetStringFilter,
6789                 NULL },
6790
6791         /* FIXME: OID is unused, but not registered yet */
6792         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
6793                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )", /* OpenLDAP authz */
6794                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6795                 NULL, authzNormalize, authzMatch,
6796                 NULL, NULL,
6797                 NULL},
6798
6799         {NULL, SLAP_MR_NONE, NULL,
6800                 NULL, NULL, NULL, NULL, NULL,
6801                 NULL }
6802 };
6803
6804 int
6805 slap_schema_init( void )
6806 {
6807         int             res;
6808         int             i;
6809
6810         /* we should only be called once (from main) */
6811         assert( schema_init_done == 0 );
6812
6813         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
6814                 res = register_syntax( &syntax_defs[i] );
6815
6816                 if ( res ) {
6817                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
6818                                  syntax_defs[i].sd_desc );
6819                         return LDAP_OTHER;
6820                 }
6821         }
6822
6823         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
6824                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
6825                         mrule_defs[i].mrd_compat_syntaxes == NULL )
6826                 {
6827                         fprintf( stderr,
6828                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
6829                                  mrule_defs[i].mrd_desc );
6830                         continue;
6831                 }
6832
6833                 res = register_matching_rule( &mrule_defs[i] );
6834
6835                 if ( res ) {
6836                         fprintf( stderr,
6837                                 "slap_schema_init: Error registering matching rule %s\n",
6838                                  mrule_defs[i].mrd_desc );
6839                         return LDAP_OTHER;
6840                 }
6841         }
6842
6843         res = slap_schema_load();
6844         schema_init_done = 1;
6845         return res;
6846 }
6847
6848 void
6849 schema_destroy( void )
6850 {
6851         oidm_destroy();
6852         oc_destroy();
6853         at_destroy();
6854         mr_destroy();
6855         mru_destroy();
6856         syn_destroy();
6857
6858         if( schema_init_done ) {
6859                 ldap_pvt_thread_mutex_destroy( &ad_index_mutex );
6860                 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
6861                 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
6862         }
6863 }