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