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