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