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