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