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