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