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