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