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