]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
csnOrderingMatch should have a normalizer
[openldap] / servers / slapd / schema_init.c
1 /* schema_init.c - init builtin schema */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2009 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20 #ifdef HAVE_LIMITS_H
21 #include <limits.h>
22 #endif
23
24 #include <ac/ctype.h>
25 #include <ac/errno.h>
26 #include <ac/string.h>
27 #include <ac/socket.h>
28
29 #include "slap.h"
30 #include "../../libraries/liblber/lber-int.h" /* get ber_ptrlen() */
31
32 #include "ldap_utf8.h"
33
34 #include "lutil.h"
35 #include "lutil_hash.h"
36 #define HASH_BYTES                              LUTIL_HASH_BYTES
37 #define HASH_CONTEXT                    lutil_HASH_CTX
38 #define HASH_Init(c)                    lutil_HASHInit(c)
39 #define HASH_Update(c,buf,len)  lutil_HASHUpdate(c,buf,len)
40 #define HASH_Final(d,c)                 lutil_HASHFinal(d,c)
41
42 /* approx matching rules */
43 #define directoryStringApproxMatchOID   "1.3.6.1.4.1.4203.666.4.4"
44 #define directoryStringApproxMatch              approxMatch
45 #define directoryStringApproxIndexer    approxIndexer
46 #define directoryStringApproxFilter             approxFilter
47 #define IA5StringApproxMatchOID                 "1.3.6.1.4.1.4203.666.4.5"
48 #define IA5StringApproxMatch                    approxMatch
49 #define IA5StringApproxIndexer                  approxIndexer
50 #define IA5StringApproxFilter                   approxFilter
51
52 /* Change Sequence Number (CSN) - much of this will change */
53 #define csnMatch                                octetStringMatch
54 #define csnOrderingMatch                octetStringOrderingMatch
55 #define csnIndexer                              generalizedTimeIndexer
56 #define csnFilter                               generalizedTimeFilter
57
58 #define authzMatch                              octetStringMatch
59
60 /* X.509 PMI ldapSyntaxes */
61 /* FIXME: need to create temporary OIDs under OpenLDAP's arc;
62  * these are currently hijacked
63  *
64  *      1.3.6.1.4.1.4203.666            OpenLDAP
65  *      1.3.6.1.4.1.4203.666.11         self-contained works
66  *      1.3.6.1.4.1.4203.666.11.10      X.509 PMI
67  *      1.3.6.1.4.1.4203.666.11.10.2    X.509 PMI ldapSyntaxes
68  *      1.3.6.1.4.1.4203.666.11.10.2.1  AttributeCertificate (supported)
69  *      1.3.6.1.4.1.4203.666.11.10.2.2  AttributeCertificateExactAssertion (supported)
70  *      1.3.6.1.4.1.4203.666.11.10.2.3  AttributeCertificateAssertion (not supported)
71  *      1.3.6.1.4.1.4203.666.11.10.2.4  AttCertPath (X-SUBST'ed right now in pmi.schema)
72  *      1.3.6.1.4.1.4203.666.11.10.2.5  PolicySyntax (X-SUBST'ed right now in pmi.schema)
73  *      1.3.6.1.4.1.4203.666.11.10.2.6  RoleSyntax (X-SUBST'ed right now in pmi.schema)
74  */
75 #if 0 /* from <draft-ietf-pkix-ldap-schema-02.txt> (expired) */
76 #define attributeCertificateSyntaxOID                   "1.2.826.0.1.3344810.7.5"
77 #define attributeCertificateExactAssertionSyntaxOID     "1.2.826.0.1.3344810.7.6"
78 #define attributeCertificateAssertionSyntaxOID          "1.2.826.0.1.3344810.7.7"
79 #else /* from OpenLDAP's experimental oid arc */
80 #define X509_PMI_SyntaxOID                              "1.3.6.1.4.1.4203.666.11.10.2"
81 #define attributeCertificateSyntaxOID                   X509_PMI_SyntaxOID ".1"
82 #define attributeCertificateExactAssertionSyntaxOID     X509_PMI_SyntaxOID ".2"
83 #define attributeCertificateAssertionSyntaxOID          X509_PMI_SyntaxOID ".3"
84 #endif
85
86 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
87 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
88 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
89 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
90
91 unsigned int index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
92 unsigned int index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
93         SLAP_INDEX_INTLEN_DEFAULT );
94
95 ldap_pvt_thread_mutex_t ad_undef_mutex;
96 ldap_pvt_thread_mutex_t oc_undef_mutex;
97
98 static int
99 generalizedTimeValidate(
100         Syntax *syntax,
101         struct berval *in );
102
103 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
104 static int
105 utcTimeValidate(
106         Syntax *syntax,
107         struct berval *in );
108 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
109
110 static int
111 inValidate(
112         Syntax *syntax,
113         struct berval *in )
114 {
115         /* no value allowed */
116         return LDAP_INVALID_SYNTAX;
117 }
118
119 static int
120 blobValidate(
121         Syntax *syntax,
122         struct berval *in )
123 {
124         /* any value allowed */
125         return LDAP_SUCCESS;
126 }
127
128 #define berValidate blobValidate
129
130 static int
131 sequenceValidate(
132         Syntax *syntax,
133         struct berval *in )
134 {
135         if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
136         if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
137
138         return LDAP_SUCCESS;
139 }
140
141 /* X.509 related stuff */
142
143 enum {
144         SLAP_X509_V1            = 0,
145         SLAP_X509_V2            = 1,
146         SLAP_X509_V3            = 2
147 };
148
149 enum {
150         SLAP_TAG_UTCTIME                = 0x17U,
151         SLAP_TAG_GENERALIZEDTIME        = 0x18U
152 };
153
154
155 #define SLAP_X509_OPTION        (LBER_CLASS_CONTEXT|LBER_CONSTRUCTED)
156
157 enum {
158         SLAP_X509_OPT_C_VERSION         = SLAP_X509_OPTION + 0,
159         SLAP_X509_OPT_C_ISSUERUNIQUEID  = LBER_CLASS_CONTEXT + 1,
160         SLAP_X509_OPT_C_SUBJECTUNIQUEID = LBER_CLASS_CONTEXT + 2,
161         SLAP_X509_OPT_C_EXTENSIONS      = SLAP_X509_OPTION + 3
162 };
163
164 enum {
165         SLAP_X509_OPT_CL_CRLEXTENSIONS  = SLAP_X509_OPTION + 0
166 };
167
168 /*
169 GeneralName ::= CHOICE {
170   otherName                 [0] INSTANCE OF OTHER-NAME,
171   rfc822Name                [1] IA5String,
172   dNSName                   [2] IA5String,
173   x400Address               [3] ORAddress,
174   directoryName             [4] Name,
175   ediPartyName              [5] EDIPartyName,
176   uniformResourceIdentifier [6] IA5String,
177   iPAddress                 [7] OCTET STRING,
178   registeredID              [8] OBJECT IDENTIFIER }
179 */
180 enum {
181         SLAP_X509_GN_OTHERNAME          = SLAP_X509_OPTION + 0,
182         SLAP_X509_GN_RFC822NAME         = SLAP_X509_OPTION + 1,
183         SLAP_X509_GN_DNSNAME            = SLAP_X509_OPTION + 2,
184         SLAP_X509_GN_X400ADDRESS        = SLAP_X509_OPTION + 3,
185         SLAP_X509_GN_DIRECTORYNAME      = SLAP_X509_OPTION + 4,
186         SLAP_X509_GN_EDIPARTYNAME       = SLAP_X509_OPTION + 5,
187         SLAP_X509_GN_URI                = SLAP_X509_OPTION + 6,
188         SLAP_X509_GN_IPADDRESS          = SLAP_X509_OPTION + 7,
189         SLAP_X509_GN_REGISTEREDID       = SLAP_X509_OPTION + 8
190 };
191
192 /* X.509 PMI related stuff */
193 enum {
194         SLAP_X509AC_V1          = 0,
195         SLAP_X509AC_V2          = 1
196 };
197
198 enum {
199         SLAP_X509AC_ISSUER      = SLAP_X509_OPTION + 0
200 };
201
202 /* X.509 certificate validation */
203 static int
204 certificateValidate( Syntax *syntax, struct berval *in )
205 {
206         BerElementBuffer berbuf;
207         BerElement *ber = (BerElement *)&berbuf;
208         ber_tag_t tag;
209         ber_len_t len;
210         ber_int_t version = SLAP_X509_V1;
211
212         ber_init2( ber, in, LBER_USE_DER );
213         tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
214         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
215         tag = ber_skip_tag( ber, &len );        /* Sequence */
216         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
217         tag = ber_peek_tag( ber, &len );
218         /* Optional version */
219         if ( tag == SLAP_X509_OPT_C_VERSION ) {
220                 tag = ber_skip_tag( ber, &len );
221                 tag = ber_get_int( ber, &version );
222                 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
223         }
224         /* NOTE: don't try to parse Serial, because it might be longer
225          * than sizeof(ber_int_t); deferred to certificateExactNormalize() */
226         tag = ber_skip_tag( ber, &len );        /* Serial */
227         if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
228         ber_skip_data( ber, len );
229         tag = ber_skip_tag( ber, &len );        /* Signature Algorithm */
230         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
231         ber_skip_data( ber, len );
232         tag = ber_skip_tag( ber, &len );        /* Issuer DN */
233         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
234         ber_skip_data( ber, len );
235         tag = ber_skip_tag( ber, &len );        /* Validity */
236         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
237         ber_skip_data( ber, len );
238         tag = ber_skip_tag( ber, &len );        /* Subject DN */
239         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
240         ber_skip_data( ber, len );
241         tag = ber_skip_tag( ber, &len );        /* Subject PublicKeyInfo */
242         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
243         ber_skip_data( ber, len );
244         tag = ber_skip_tag( ber, &len );
245         if ( tag == SLAP_X509_OPT_C_ISSUERUNIQUEID ) {  /* issuerUniqueID */
246                 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
247                 ber_skip_data( ber, len );
248                 tag = ber_skip_tag( ber, &len );
249         }
250         if ( tag == SLAP_X509_OPT_C_SUBJECTUNIQUEID ) { /* subjectUniqueID */
251                 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
252                 ber_skip_data( ber, len );
253                 tag = ber_skip_tag( ber, &len );
254         }
255         if ( tag == SLAP_X509_OPT_C_EXTENSIONS ) {      /* Extensions */
256                 if ( version < SLAP_X509_V3 ) return LDAP_INVALID_SYNTAX;
257                 tag = ber_skip_tag( ber, &len );
258                 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
259                 ber_skip_data( ber, len );
260                 tag = ber_skip_tag( ber, &len );
261         }
262         /* signatureAlgorithm */
263         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
264         ber_skip_data( ber, len );
265         tag = ber_skip_tag( ber, &len );
266         /* Signature */
267         if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX; 
268         ber_skip_data( ber, len );
269         tag = ber_skip_tag( ber, &len );
270         /* Must be at end now */
271         if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
272         return LDAP_SUCCESS;
273 }
274
275 /* X.509 certificate list validation */
276 static int
277 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                         BER_BVZERO( normalized );
2818                         return LDAP_INVALID_SYNTAX;
2819                 }
2820
2821                 if( j & 1 ) {
2822                         octet |= nibble;
2823                         normalized->bv_val[j>>1] = octet;
2824                 } else {
2825                         octet = nibble << 4;
2826                 }
2827                 j++;
2828         }
2829
2830         normalized->bv_val[normalized->bv_len] = 0;
2831         return LDAP_SUCCESS;
2832 }
2833
2834
2835
2836 int
2837 numericStringValidate(
2838         Syntax *syntax,
2839         struct berval *in )
2840 {
2841         ber_len_t i;
2842
2843         if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2844
2845         for(i=0; i < in->bv_len; i++) {
2846                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2847                         return LDAP_INVALID_SYNTAX;
2848                 }
2849         }
2850
2851         return LDAP_SUCCESS;
2852 }
2853
2854 static int
2855 numericStringNormalize(
2856         slap_mask_t usage,
2857         Syntax *syntax,
2858         MatchingRule *mr,
2859         struct berval *val,
2860         struct berval *normalized,
2861         void *ctx )
2862 {
2863         /* removal all spaces */
2864         char *p, *q;
2865
2866         assert( !BER_BVISEMPTY( val ) );
2867
2868         normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2869
2870         p = val->bv_val;
2871         q = normalized->bv_val;
2872
2873         while ( *p ) {
2874                 if ( ASCII_SPACE( *p ) ) {
2875                         /* Ignore whitespace */
2876                         p++;
2877                 } else {
2878                         *q++ = *p++;
2879                 }
2880         }
2881
2882         /* we should have copied no more than is in val */
2883         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2884
2885         /* null terminate */
2886         *q = '\0';
2887
2888         normalized->bv_len = q - normalized->bv_val;
2889
2890         if( BER_BVISEMPTY( normalized ) ) {
2891                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2892                 normalized->bv_val[0] = ' ';
2893                 normalized->bv_val[1] = '\0';
2894                 normalized->bv_len = 1;
2895         }
2896
2897         return LDAP_SUCCESS;
2898 }
2899
2900 /*
2901  * Integer conversion macros that will use the largest available
2902  * type.
2903  */
2904 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
2905 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
2906 # define SLAP_LONG           long long
2907 #else
2908 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
2909 # define SLAP_LONG           long
2910 #endif /* HAVE_STRTOLL ... */
2911
2912 static int
2913 integerBitAndMatch(
2914         int *matchp,
2915         slap_mask_t flags,
2916         Syntax *syntax,
2917         MatchingRule *mr,
2918         struct berval *value,
2919         void *assertedValue )
2920 {
2921         SLAP_LONG lValue, lAssertedValue;
2922
2923         errno = 0;
2924         /* safe to assume integers are NUL terminated? */
2925         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2926         if( errno == ERANGE )
2927         {
2928                 return LDAP_CONSTRAINT_VIOLATION;
2929         }
2930
2931         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2932                 NULL, 10);
2933         if( errno == ERANGE )
2934         {
2935                 return LDAP_CONSTRAINT_VIOLATION;
2936         }
2937
2938         *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2939         return LDAP_SUCCESS;
2940 }
2941
2942 static int
2943 integerBitOrMatch(
2944         int *matchp,
2945         slap_mask_t flags,
2946         Syntax *syntax,
2947         MatchingRule *mr,
2948         struct berval *value,
2949         void *assertedValue )
2950 {
2951         SLAP_LONG lValue, lAssertedValue;
2952
2953         errno = 0;
2954         /* safe to assume integers are NUL terminated? */
2955         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2956         if( errno == ERANGE )
2957         {
2958                 return LDAP_CONSTRAINT_VIOLATION;
2959         }
2960
2961         lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2962                 NULL, 10);
2963         if( errno == ERANGE )
2964         {
2965                 return LDAP_CONSTRAINT_VIOLATION;
2966         }
2967
2968         *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2969         return LDAP_SUCCESS;
2970 }
2971
2972 static int
2973 checkNum( struct berval *in, struct berval *out )
2974 {
2975         /* parse serialNumber */
2976         ber_len_t neg = 0, extra = 0;
2977         char first = '\0';
2978
2979         out->bv_val = in->bv_val;
2980         out->bv_len = 0;
2981
2982         if ( out->bv_val[0] == '-' ) {
2983                 neg++;
2984                 out->bv_len++;
2985         }
2986
2987         if ( strncasecmp( out->bv_val, "0x", STRLENOF("0x") ) == 0 ) {
2988                 first = out->bv_val[2];
2989                 extra = 2;
2990
2991                 out->bv_len += STRLENOF("0x");
2992                 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
2993                         if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
2994                 }
2995
2996         } else if ( out->bv_val[0] == '\'' ) {
2997                 first = out->bv_val[1];
2998                 extra = 3;
2999
3000                 out->bv_len += STRLENOF("'");
3001
3002                 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3003                         if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3004                 }
3005                 if ( strncmp( &out->bv_val[out->bv_len], "'H", STRLENOF("'H") ) != 0 ) {
3006                         return -1;
3007                 }
3008                 out->bv_len += STRLENOF("'H");
3009
3010         } else {
3011                 first = out->bv_val[0];
3012                 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3013                         if ( !ASCII_DIGIT( out->bv_val[out->bv_len] ) ) break;
3014                 }
3015         }
3016
3017         if ( !( out->bv_len > neg ) ) {
3018                 return -1;
3019         }
3020
3021         if ( ( out->bv_len > extra + 1 + neg ) && ( first == '0' ) ) {
3022                 return -1;
3023         }
3024
3025         return 0;
3026 }
3027
3028 static int
3029 serialNumberAndIssuerCheck(
3030         struct berval *in,
3031         struct berval *sn,
3032         struct berval *is,
3033         void *ctx )
3034 {
3035         ber_len_t n;
3036
3037         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3038
3039         if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3040                 /* Parse old format */
3041                 is->bv_val = ber_bvchr( in, '$' );
3042                 if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
3043
3044                 sn->bv_val = in->bv_val;
3045                 sn->bv_len = is->bv_val - in->bv_val;
3046
3047                 is->bv_val++;
3048                 is->bv_len = in->bv_len - (sn->bv_len + 1);
3049
3050                 /* eat leading zeros */
3051                 for( n=0; n < (sn->bv_len-1); n++ ) {
3052                         if( sn->bv_val[n] != '0' ) break;
3053                 }
3054                 sn->bv_val += n;
3055                 sn->bv_len -= n;
3056
3057                 for( n=0; n < sn->bv_len; n++ ) {
3058                         if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3059                 }
3060
3061         } else {
3062                 /* Parse GSER format */ 
3063                 enum {
3064                         HAVE_NONE = 0x0,
3065                         HAVE_ISSUER = 0x1,
3066                         HAVE_SN = 0x2,
3067                         HAVE_ALL = ( HAVE_ISSUER | HAVE_SN )
3068                 } have = HAVE_NONE;
3069
3070                 int numdquotes = 0;
3071                 struct berval x = *in;
3072                 struct berval ni;
3073                 x.bv_val++;
3074                 x.bv_len -= 2;
3075
3076                 do {
3077                         /* eat leading spaces */
3078                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3079                                 /* empty */;
3080                         }
3081
3082                         /* should be at issuer or serialNumber NamedValue */
3083                         if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3084                                 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3085
3086                                 /* parse issuer */
3087                                 x.bv_val += STRLENOF("issuer");
3088                                 x.bv_len -= STRLENOF("issuer");
3089
3090                                 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3091                                 x.bv_val++;
3092                                 x.bv_len--;
3093
3094                                 /* eat leading spaces */
3095                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3096                                         /* empty */;
3097                                 }
3098
3099                                 /* For backward compatibility, this part is optional */
3100                                 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) == 0 ) {
3101                                         x.bv_val += STRLENOF("rdnSequence:");
3102                                         x.bv_len -= STRLENOF("rdnSequence:");
3103                                 }
3104
3105                                 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3106                                 x.bv_val++;
3107                                 x.bv_len--;
3108
3109                                 is->bv_val = x.bv_val;
3110                                 is->bv_len = 0;
3111
3112                                 for ( ; is->bv_len < x.bv_len; ) {
3113                                         if ( is->bv_val[is->bv_len] != '"' ) {
3114                                                 is->bv_len++;
3115                                                 continue;
3116                                         }
3117                                         if ( is->bv_val[is->bv_len+1] == '"' ) {
3118                                                 /* double dquote */
3119                                                 is->bv_len += 2;
3120                                                 continue;
3121                                         }
3122                                         break;
3123                                 }
3124                                 x.bv_val += is->bv_len + 1;
3125                                 x.bv_len -= is->bv_len + 1;
3126
3127                                 have |= HAVE_ISSUER;
3128
3129                         } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 )
3130                         {
3131                                 if ( have & HAVE_SN ) return LDAP_INVALID_SYNTAX;
3132
3133                                 /* parse serialNumber */
3134                                 x.bv_val += STRLENOF("serialNumber");
3135                                 x.bv_len -= STRLENOF("serialNumber");
3136
3137                                 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3138                                 x.bv_val++;
3139                                 x.bv_len--;
3140
3141                                 /* eat leading spaces */
3142                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3143                                         /* empty */;
3144                                 }
3145
3146                                 if ( checkNum( &x, sn ) ) {
3147                                         return LDAP_INVALID_SYNTAX;
3148                                 }
3149
3150                                 x.bv_val += sn->bv_len;
3151                                 x.bv_len -= sn->bv_len;
3152
3153                                 have |= HAVE_SN;
3154
3155                         } else {
3156                                 return LDAP_INVALID_SYNTAX;
3157                         }
3158
3159                         /* eat leading spaces */
3160                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3161                                 /* empty */;
3162                         }
3163
3164                         if ( have == HAVE_ALL ) {
3165                                 break;
3166                         }
3167
3168                         if ( x.bv_val[0] != ',' ) {
3169                                 return LDAP_INVALID_SYNTAX;
3170                         }
3171
3172                         x.bv_val++;
3173                         x.bv_len--;
3174                 } while ( 1 );
3175
3176                 /* should have no characters left... */
3177                 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3178
3179                 if ( numdquotes == 0 ) {
3180                         ber_dupbv_x( &ni, is, ctx );
3181
3182                 } else {
3183                         ber_len_t src, dst;
3184
3185                         ni.bv_len = is->bv_len - numdquotes;
3186                         ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3187                         for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3188                                 if ( is->bv_val[src] == '"' ) {
3189                                         src++;
3190                                 }
3191                                 ni.bv_val[dst] = is->bv_val[src];
3192                         }
3193                         ni.bv_val[dst] = '\0';
3194                 }
3195                         
3196                 *is = ni;
3197         }
3198
3199         return 0;
3200 }
3201         
3202 static int
3203 serialNumberAndIssuerValidate(
3204         Syntax *syntax,
3205         struct berval *in )
3206 {
3207         int rc;
3208         struct berval sn, i;
3209
3210         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3211                 in->bv_val, 0, 0 );
3212
3213         rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3214         if ( rc ) {
3215                 goto done;
3216         }
3217
3218         /* validate DN -- doesn't handle double dquote */ 
3219         rc = dnValidate( NULL, &i );
3220         if ( rc ) {
3221                 rc = LDAP_INVALID_SYNTAX;
3222         }
3223
3224         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3225                 slap_sl_free( i.bv_val, NULL );
3226         }
3227
3228         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: <%s> err=%d\n",
3229                 in->bv_val, rc, 0 );
3230
3231 done:;
3232         return rc;
3233 }
3234
3235 static int
3236 serialNumberAndIssuerPretty(
3237         Syntax *syntax,
3238         struct berval *in,
3239         struct berval *out,
3240         void *ctx )
3241 {
3242         int rc;
3243         struct berval sn, i, ni = BER_BVNULL;
3244         char *p;
3245
3246         assert( in != NULL );
3247         assert( out != NULL );
3248
3249         BER_BVZERO( out );
3250
3251         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3252                 in->bv_val, 0, 0 );
3253
3254         rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3255         if ( rc ) {
3256                 goto done;
3257         }
3258
3259         rc = dnPretty( syntax, &i, &ni, ctx );
3260
3261         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3262                 slap_sl_free( i.bv_val, ctx );
3263         }
3264
3265         if ( rc ) {
3266                 rc = LDAP_INVALID_SYNTAX;
3267                 goto done;
3268         }
3269
3270         /* make room from sn + "$" */
3271         out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3272                 + sn.bv_len + ni.bv_len;
3273         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3274
3275         if ( out->bv_val == NULL ) {
3276                 out->bv_len = 0;
3277                 rc = LDAP_OTHER;
3278                 goto done;
3279         }
3280
3281         p = out->bv_val;
3282         p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3283         p = lutil_strncopy( p, sn.bv_val, sn.bv_len );
3284         p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3285         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
3286         p = lutil_strcopy( p, /*{*/ "\" }" );
3287
3288         assert( p == &out->bv_val[out->bv_len] );
3289
3290 done:;
3291         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s> => <%s>\n",
3292                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3293
3294         slap_sl_free( ni.bv_val, ctx );
3295
3296         return LDAP_SUCCESS; 
3297 }
3298
3299 static int
3300 slap_bin2hex(
3301         struct berval *in,
3302         struct berval *out,
3303         void *ctx )
3304
3305 {       
3306         /* Use hex format. '123456789abcdef'H */
3307         unsigned char *ptr, zero = '\0';
3308         char *sptr;
3309         int first;
3310         ber_len_t i, len, nlen;
3311
3312         assert( in != NULL );
3313         assert( !BER_BVISNULL( in ) );
3314         assert( out != NULL );
3315         assert( !BER_BVISNULL( out ) );
3316
3317         ptr = (unsigned char *)in->bv_val;
3318         len = in->bv_len;
3319
3320         /* Check for minimal encodings */
3321         if ( len > 1 ) {
3322                 if ( ptr[0] & 0x80 ) {
3323                         if ( ( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ) ) {
3324                                 return -1;
3325                         }
3326
3327                 } else if ( ptr[0] == 0 ) {
3328                         if ( !( ptr[1] & 0x80 ) ) {
3329                                 return -1;
3330                         }
3331                         len--;
3332                         ptr++;
3333                 }
3334
3335         } else if ( len == 0 ) {
3336                 /* FIXME: this should not be possible,
3337                  * since a value of zero would have length 1 */
3338                 len = 1;
3339                 ptr = &zero;
3340         }
3341
3342         first = !( ptr[0] & 0xf0U );
3343         nlen = len * 2 - first + STRLENOF("''H"); /* quotes, H */
3344         if ( nlen >= out->bv_len ) {
3345                 out->bv_val = slap_sl_malloc( nlen + 1, ctx );
3346         }
3347         sptr = out->bv_val;
3348         *sptr++ = '\'';
3349         i = 0;
3350         if ( first ) {
3351                 sprintf( sptr, "%01X", ( ptr[0] & 0x0fU ) );
3352                 sptr++;
3353                 i = 1;
3354         }
3355         for ( ; i < len; i++ ) {
3356                 sprintf( sptr, "%02X", ptr[i] );
3357                 sptr += 2;
3358         }
3359         *sptr++ = '\'';
3360         *sptr++ = 'H';
3361         *sptr = '\0';
3362
3363         assert( sptr == &out->bv_val[nlen] );
3364
3365         out->bv_len = nlen;
3366
3367         return 0;
3368 }
3369
3370 #define SLAP_SN_BUFLEN  (64)
3371
3372 /*
3373  * This routine is called by certificateExactNormalize when
3374  * certificateExactNormalize receives a search string instead of
3375  * a certificate. This routine checks if the search value is valid
3376  * and then returns the normalized value
3377  */
3378 static int
3379 serialNumberAndIssuerNormalize(
3380         slap_mask_t usage,
3381         Syntax *syntax,
3382         MatchingRule *mr,
3383         struct berval *in,
3384         struct berval *out,
3385         void *ctx )
3386 {
3387         struct berval sn, sn2, sn3, i, ni;
3388         char sbuf2[SLAP_SN_BUFLEN];
3389         char sbuf3[SLAP_SN_BUFLEN];
3390         char *p;
3391         int rc;
3392
3393         assert( in != NULL );
3394         assert( out != NULL );
3395
3396         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3397                 in->bv_val, 0, 0 );
3398
3399         rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3400         if ( rc ) {
3401                 return rc;
3402         }
3403
3404         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3405
3406         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3407                 slap_sl_free( i.bv_val, ctx );
3408         }
3409
3410         if ( rc ) {
3411                 return LDAP_INVALID_SYNTAX;
3412         }
3413
3414         /* Convert sn to canonical hex */
3415         sn2.bv_val = sbuf2;
3416         if ( sn.bv_len > sizeof( sbuf2 ) ) {
3417                 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
3418         }
3419         sn2.bv_len = sn.bv_len;
3420         if ( lutil_str2bin( &sn, &sn2, ctx )) {
3421                 rc = LDAP_INVALID_SYNTAX;
3422                 goto func_leave;
3423         }
3424
3425         sn3.bv_val = sbuf3;
3426         sn3.bv_len = sizeof(sbuf3);
3427         if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
3428                 rc = LDAP_INVALID_SYNTAX;
3429                 goto func_leave;
3430         }
3431
3432         out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3433                 + sn3.bv_len + ni.bv_len;
3434         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3435
3436         if ( out->bv_val == NULL ) {
3437                 out->bv_len = 0;
3438                 rc = LDAP_OTHER;
3439                 goto func_leave;
3440         }
3441
3442         p = out->bv_val;
3443
3444         p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3445         p = lutil_strncopy( p, sn3.bv_val, sn3.bv_len );
3446         p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3447         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
3448         p = lutil_strcopy( p, /*{*/ "\" }" );
3449
3450         assert( p == &out->bv_val[out->bv_len] );
3451
3452 func_leave:
3453         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n",
3454                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3455
3456         if ( sn2.bv_val != sbuf2 ) {
3457                 slap_sl_free( sn2.bv_val, ctx );
3458         }
3459
3460         if ( sn3.bv_val != sbuf3 ) {
3461                 slap_sl_free( sn3.bv_val, ctx );
3462         }
3463
3464         slap_sl_free( ni.bv_val, ctx );
3465
3466         return rc;
3467 }
3468
3469 static int
3470 certificateExactNormalize(
3471         slap_mask_t usage,
3472         Syntax *syntax,
3473         MatchingRule *mr,
3474         struct berval *val,
3475         struct berval *normalized,
3476         void *ctx )
3477 {
3478         BerElementBuffer berbuf;
3479         BerElement *ber = (BerElement *)&berbuf;
3480         ber_tag_t tag;
3481         ber_len_t len;
3482         ber_int_t i;
3483         char serialbuf2[SLAP_SN_BUFLEN];
3484         struct berval sn, sn2 = BER_BVNULL;
3485         struct berval issuer_dn = BER_BVNULL, bvdn;
3486         char *p;
3487         int rc = LDAP_INVALID_SYNTAX;
3488
3489         assert( val != NULL );
3490
3491         Debug( LDAP_DEBUG_TRACE, ">>> certificateExactNormalize: <%p, %lu>\n",
3492                 val->bv_val, val->bv_len, 0 );
3493
3494         if ( BER_BVISEMPTY( val ) ) goto done;
3495
3496         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3497                 return serialNumberAndIssuerNormalize( 0, NULL, NULL, val, normalized, ctx );
3498         }
3499
3500         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3501
3502         ber_init2( ber, val, LBER_USE_DER );
3503         tag = ber_skip_tag( ber, &len );        /* Signed Sequence */
3504         tag = ber_skip_tag( ber, &len );        /* Sequence */
3505         tag = ber_peek_tag( ber, &len );        /* Optional version? */
3506         if ( tag == SLAP_X509_OPT_C_VERSION ) {
3507                 tag = ber_skip_tag( ber, &len );
3508                 tag = ber_get_int( ber, &i );   /* version */
3509         }
3510
3511         /* NOTE: move the test here from certificateValidate,
3512          * so that we can validate certs with serial longer
3513          * than sizeof(ber_int_t) */
3514         tag = ber_skip_tag( ber, &len );        /* serial */
3515         sn.bv_len = len;
3516         sn.bv_val = (char *)ber->ber_ptr;
3517         sn2.bv_val = serialbuf2;
3518         sn2.bv_len = sizeof(serialbuf2);
3519         if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
3520                 rc = LDAP_INVALID_SYNTAX;
3521                 goto done;
3522         }
3523         ber_skip_data( ber, len );
3524
3525         tag = ber_skip_tag( ber, &len );        /* SignatureAlg */
3526         ber_skip_data( ber, len );
3527         tag = ber_peek_tag( ber, &len );        /* IssuerDN */
3528         len = ber_ptrlen( ber );
3529         bvdn.bv_val = val->bv_val + len;
3530         bvdn.bv_len = val->bv_len - len;
3531
3532         rc = dnX509normalize( &bvdn, &issuer_dn );
3533         if ( rc != LDAP_SUCCESS ) goto done;
3534
3535         normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3536                 + sn2.bv_len + issuer_dn.bv_len;
3537         normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
3538
3539         p = normalized->bv_val;
3540
3541         p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3542         p = lutil_strncopy( p, sn2.bv_val, sn2.bv_len );
3543         p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3544         p = lutil_strncopy( p, issuer_dn.bv_val, issuer_dn.bv_len );
3545         p = lutil_strcopy( p, /*{*/ "\" }" );
3546
3547         rc = LDAP_SUCCESS;
3548
3549 done:
3550         Debug( LDAP_DEBUG_TRACE, "<<< certificateExactNormalize: <%p, %lu> => <%s>\n",
3551                 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
3552
3553         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3554         if ( sn2.bv_val != serialbuf2 ) ber_memfree_x( sn2.bv_val, ctx );
3555
3556         return rc;
3557 }
3558
3559 /* X.509 PKI certificateList stuff */
3560 static int
3561 checkTime( struct berval *in, struct berval *out )
3562 {
3563         int rc;
3564         ber_len_t i;
3565         char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3566         struct berval bv;
3567
3568         assert( in != NULL );
3569         assert( !BER_BVISNULL( in ) );
3570         assert( !BER_BVISEMPTY( in ) );
3571
3572         if ( in->bv_len < STRLENOF( "YYmmddHHMMSSZ" ) ) {
3573                 return -1;
3574         }
3575
3576         if ( out != NULL ) {
3577                 assert( !BER_BVISNULL( out ) );
3578                 assert( out->bv_len >= sizeof( buf ) );
3579                 bv.bv_val = out->bv_val;
3580
3581         } else {
3582                 bv.bv_val = buf;
3583         }
3584
3585         for ( i = 0; i < STRLENOF( "YYYYmmddHHMMSS" ); i++ ) {
3586                 if ( !ASCII_DIGIT( in->bv_val[i] ) ) break;
3587         }
3588
3589         if ( in->bv_val[i] != 'Z' ) {
3590                 return -1;
3591         }
3592         i++;
3593
3594         if ( i != in->bv_len ) {
3595                 return -1;
3596         }
3597
3598         if ( i == STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3599                 lutil_strncopy( bv.bv_val, in->bv_val, i );
3600                 bv.bv_len = i;
3601                 
3602         } else if ( i == STRLENOF( "YYmmddHHMMSSZ" ) ) {
3603                 char *p = bv.bv_val;
3604                 if ( in->bv_val[0] < '7' ) {
3605                         p = lutil_strcopy( p, "20" );
3606
3607                 } else {
3608                         p = lutil_strcopy( p, "19" );
3609                 }
3610                 lutil_strncopy( p, in->bv_val, i );
3611                 bv.bv_len = 2 + i;
3612
3613         } else {
3614                 return -1;
3615         }
3616
3617         rc = generalizedTimeValidate( NULL, &bv );
3618         if ( rc == LDAP_SUCCESS && out != NULL ) {
3619                 out->bv_len = bv.bv_len;
3620         }
3621
3622         return rc != LDAP_SUCCESS;
3623 }
3624
3625 static int
3626 issuerAndThisUpdateCheck(
3627         struct berval *in,
3628         struct berval *is,
3629         struct berval *tu,
3630         void *ctx )
3631 {
3632         int numdquotes = 0;
3633         struct berval x = *in;
3634         struct berval ni = BER_BVNULL;
3635         /* Parse GSER format */ 
3636         enum {
3637                 HAVE_NONE = 0x0,
3638                 HAVE_ISSUER = 0x1,
3639                 HAVE_THISUPDATE = 0x2,
3640                 HAVE_ALL = ( HAVE_ISSUER | HAVE_THISUPDATE )
3641         } have = HAVE_NONE;
3642
3643
3644         if ( in->bv_len < STRLENOF( "{issuer \"\",thisUpdate \"YYMMDDhhmmssZ\"}" ) ) return LDAP_INVALID_SYNTAX;
3645
3646         if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3647                 return LDAP_INVALID_SYNTAX;
3648         }
3649
3650         x.bv_val++;
3651         x.bv_len -= STRLENOF("{}");
3652
3653         do {
3654                 /* eat leading spaces */
3655                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3656                         /* empty */;
3657                 }
3658
3659                 /* should be at issuer or thisUpdate */
3660                 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3661                         if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3662
3663                         /* parse issuer */
3664                         x.bv_val += STRLENOF("issuer");
3665                         x.bv_len -= STRLENOF("issuer");
3666
3667                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3668                         x.bv_val++;
3669                         x.bv_len--;
3670
3671                         /* eat leading spaces */
3672                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3673                                 /* empty */;
3674                         }
3675
3676                         /* For backward compatibility, this part is optional */
3677                         if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) != 0 ) {
3678                                 return LDAP_INVALID_SYNTAX;
3679                         }
3680                         x.bv_val += STRLENOF("rdnSequence:");
3681                         x.bv_len -= STRLENOF("rdnSequence:");
3682
3683                         if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3684                         x.bv_val++;
3685                         x.bv_len--;
3686
3687                         is->bv_val = x.bv_val;
3688                         is->bv_len = 0;
3689
3690                         for ( ; is->bv_len < x.bv_len; ) {
3691                                 if ( is->bv_val[is->bv_len] != '"' ) {
3692                                         is->bv_len++;
3693                                         continue;
3694                                 }
3695                                 if ( is->bv_val[is->bv_len+1] == '"' ) {
3696                                         /* double dquote */
3697                                         is->bv_len += 2;
3698                                         continue;
3699                                 }
3700                                 break;
3701                         }
3702                         x.bv_val += is->bv_len + 1;
3703                         x.bv_len -= is->bv_len + 1;
3704
3705                         have |= HAVE_ISSUER;
3706
3707                 } else if ( strncasecmp( x.bv_val, "thisUpdate", STRLENOF("thisUpdate") ) == 0 )
3708                 {
3709                         if ( have & HAVE_THISUPDATE ) return LDAP_INVALID_SYNTAX;
3710
3711                         /* parse thisUpdate */
3712                         x.bv_val += STRLENOF("thisUpdate");
3713                         x.bv_len -= STRLENOF("thisUpdate");
3714
3715                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3716                         x.bv_val++;
3717                         x.bv_len--;
3718
3719                         /* eat leading spaces */
3720                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3721                                 /* empty */;
3722                         }
3723
3724                         if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3725                         x.bv_val++;
3726                         x.bv_len--;
3727
3728                         tu->bv_val = x.bv_val;
3729                         tu->bv_len = 0;
3730
3731                         for ( ; tu->bv_len < x.bv_len; tu->bv_len++ ) {
3732                                 if ( tu->bv_val[tu->bv_len] == '"' ) {
3733                                         break;
3734                                 }
3735                         }
3736                         x.bv_val += tu->bv_len + 1;
3737                         x.bv_len -= tu->bv_len + 1;
3738
3739                         have |= HAVE_THISUPDATE;
3740
3741                 } else {
3742                         return LDAP_INVALID_SYNTAX;
3743                 }
3744
3745                 /* eat leading spaces */
3746                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3747                         /* empty */;
3748                 }
3749
3750                 if ( have == HAVE_ALL ) {
3751                         break;
3752                 }
3753
3754                 if ( x.bv_val[0] != ',' ) {
3755                         return LDAP_INVALID_SYNTAX;
3756                 }
3757
3758                 x.bv_val++;
3759                 x.bv_len--;
3760         } while ( 1 );
3761
3762         /* should have no characters left... */
3763         if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3764
3765         if ( numdquotes == 0 ) {
3766                 ber_dupbv_x( &ni, is, ctx );
3767
3768         } else {
3769                 ber_len_t src, dst;
3770
3771                 ni.bv_len = is->bv_len - numdquotes;
3772                 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3773                 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3774                         if ( is->bv_val[src] == '"' ) {
3775                                 src++;
3776                         }
3777                         ni.bv_val[dst] = is->bv_val[src];
3778                 }
3779                 ni.bv_val[dst] = '\0';
3780         }
3781                 
3782         *is = ni;
3783
3784         return 0;
3785 }
3786
3787 static int
3788 issuerAndThisUpdateValidate(
3789         Syntax *syntax,
3790         struct berval *in )
3791 {
3792         int rc;
3793         struct berval i, tu;
3794
3795         Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateValidate: <%s>\n",
3796                 in->bv_val, 0, 0 );
3797
3798         rc = issuerAndThisUpdateCheck( in, &i, &tu, NULL );
3799         if ( rc ) {
3800                 goto done;
3801         }
3802
3803         /* validate DN -- doesn't handle double dquote */ 
3804         rc = dnValidate( NULL, &i );
3805         if ( rc ) {
3806                 rc = LDAP_INVALID_SYNTAX;
3807
3808         } else if ( checkTime( &tu, NULL ) ) {
3809                 rc = LDAP_INVALID_SYNTAX;
3810         }
3811
3812         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3813                 slap_sl_free( i.bv_val, NULL );
3814         }
3815
3816         Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateValidate: <%s> err=%d\n",
3817                 in->bv_val, rc, 0 );
3818
3819 done:;
3820         return rc;
3821 }
3822
3823 static int
3824 issuerAndThisUpdatePretty(
3825         Syntax *syntax,
3826         struct berval *in,
3827         struct berval *out,
3828         void *ctx )
3829 {
3830         int rc;
3831         struct berval i, tu, ni = BER_BVNULL;
3832         char *p;
3833
3834         assert( in != NULL );
3835         assert( out != NULL );
3836
3837         BER_BVZERO( out );
3838
3839         Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdatePretty: <%s>\n",
3840                 in->bv_val, 0, 0 );
3841
3842         rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
3843         if ( rc ) {
3844                 goto done;
3845         }
3846
3847         rc = dnPretty( syntax, &i, &ni, ctx );
3848
3849         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3850                 slap_sl_free( i.bv_val, ctx );
3851         }
3852
3853         if ( rc || checkTime( &tu, NULL ) ) {
3854                 rc = LDAP_INVALID_SYNTAX;
3855                 goto done;
3856         }
3857
3858         /* make room */
3859         out->bv_len = STRLENOF("{ issuer rdnSequence:\"\", thisUpdate \"\" }")
3860                 + ni.bv_len + tu.bv_len;
3861         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3862
3863         if ( out->bv_val == NULL ) {
3864                 out->bv_len = 0;
3865                 rc = LDAP_OTHER;
3866                 goto done;
3867         }
3868
3869         p = out->bv_val;
3870         p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
3871         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
3872         p = lutil_strcopy( p, "\", thisUpdate \"" );
3873         p = lutil_strncopy( p, tu.bv_val, tu.bv_len );
3874         p = lutil_strcopy( p, /*{*/ "\" }" );
3875
3876         assert( p == &out->bv_val[out->bv_len] );
3877
3878 done:;
3879         Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n",
3880                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3881
3882         slap_sl_free( ni.bv_val, ctx );
3883
3884         return rc; 
3885 }
3886
3887 static int
3888 issuerAndThisUpdateNormalize(
3889         slap_mask_t usage,
3890         Syntax *syntax,
3891         MatchingRule *mr,
3892         struct berval *in,
3893         struct berval *out,
3894         void *ctx )
3895 {
3896         struct berval i, ni, tu, tu2;
3897         char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3898         char *p;
3899         int rc;
3900
3901         assert( in != NULL );
3902         assert( out != NULL );
3903
3904         Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
3905                 in->bv_val, 0, 0 );
3906
3907         rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
3908         if ( rc ) {
3909                 return rc;
3910         }
3911
3912         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3913
3914         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3915                 slap_sl_free( i.bv_val, ctx );
3916         }
3917
3918         tu2.bv_val = sbuf;
3919         tu2.bv_len = sizeof( sbuf );
3920         if ( rc || checkTime( &tu, &tu2 ) ) {
3921                 return LDAP_INVALID_SYNTAX;
3922         }
3923
3924         out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
3925                 + ni.bv_len + tu2.bv_len;
3926         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3927
3928         if ( out->bv_val == NULL ) {
3929                 out->bv_len = 0;
3930                 rc = LDAP_OTHER;
3931                 goto func_leave;
3932         }
3933
3934         p = out->bv_val;
3935
3936         p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
3937         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
3938         p = lutil_strcopy( p, "\", thisUpdate \"" );
3939         p = lutil_strncopy( p, tu2.bv_val, tu2.bv_len );
3940         p = lutil_strcopy( p, /*{*/ "\" }" );
3941
3942         assert( p == &out->bv_val[out->bv_len] );
3943
3944 func_leave:
3945         Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
3946                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3947
3948         slap_sl_free( ni.bv_val, ctx );
3949
3950         return rc;
3951 }
3952
3953 static int
3954 certificateListExactNormalize(
3955         slap_mask_t usage,
3956         Syntax *syntax,
3957         MatchingRule *mr,
3958         struct berval *val,
3959         struct berval *normalized,
3960         void *ctx )
3961 {
3962         BerElementBuffer berbuf;
3963         BerElement *ber = (BerElement *)&berbuf;
3964         ber_tag_t tag;
3965         ber_len_t len;
3966         ber_int_t version;
3967         struct berval issuer_dn = BER_BVNULL, bvdn,
3968                 thisUpdate, bvtu;
3969         char *p, tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3970         int rc = LDAP_INVALID_SYNTAX;
3971
3972         assert( val != NULL );
3973
3974         Debug( LDAP_DEBUG_TRACE, ">>> certificateListExactNormalize: <%p, %lu>\n",
3975                 val->bv_val, val->bv_len, 0 );
3976
3977         if ( BER_BVISEMPTY( val ) ) goto done;
3978
3979         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3980                 return issuerAndThisUpdateNormalize( 0, NULL, NULL, val, normalized, ctx );
3981         }
3982
3983         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3984
3985         ber_init2( ber, val, LBER_USE_DER );
3986         tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
3987         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
3988         tag = ber_skip_tag( ber, &len );        /* Sequence */
3989         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
3990         tag = ber_peek_tag( ber, &len );
3991         /* Optional version */
3992         if ( tag == LBER_INTEGER ) {
3993                 tag = ber_get_int( ber, &version );
3994                 assert( tag == LBER_INTEGER );
3995                 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
3996         }
3997         tag = ber_skip_tag( ber, &len );        /* Signature Algorithm */
3998         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
3999         ber_skip_data( ber, len );
4000
4001         tag = ber_peek_tag( ber, &len );        /* IssuerDN */
4002         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4003         len = ber_ptrlen( ber );
4004         bvdn.bv_val = val->bv_val + len;
4005         bvdn.bv_len = val->bv_len - len;
4006         tag = ber_skip_tag( ber, &len );
4007         ber_skip_data( ber, len );
4008
4009         tag = ber_skip_tag( ber, &len );        /* thisUpdate */
4010         /* Time is a CHOICE { UTCTime, GeneralizedTime } */
4011         if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
4012         bvtu.bv_val = (char *)ber->ber_ptr;
4013         bvtu.bv_len = len;
4014
4015         rc = dnX509normalize( &bvdn, &issuer_dn );
4016         if ( rc != LDAP_SUCCESS ) goto done;
4017
4018         thisUpdate.bv_val = tubuf;
4019         thisUpdate.bv_len = sizeof(tubuf);
4020         if ( checkTime( &bvtu, &thisUpdate ) ) {
4021                 rc = LDAP_INVALID_SYNTAX;
4022                 goto done;
4023         }
4024
4025         normalized->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4026                 + issuer_dn.bv_len + thisUpdate.bv_len;
4027         normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4028
4029         p = normalized->bv_val;
4030
4031         p = lutil_strcopy( p, "{ issuer rdnSequence:\"" );
4032         p = lutil_strncopy( p, issuer_dn.bv_val, issuer_dn.bv_len );
4033         p = lutil_strcopy( p, "\", thisUpdate \"" );
4034         p = lutil_strncopy( p, thisUpdate.bv_val, thisUpdate.bv_len );
4035         p = lutil_strcopy( p, /*{*/ "\" }" );
4036
4037         rc = LDAP_SUCCESS;
4038
4039 done:
4040         Debug( LDAP_DEBUG_TRACE, "<<< certificateListExactNormalize: <%p, %lu> => <%s>\n",
4041                 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
4042
4043         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4044
4045         return rc;
4046 }
4047
4048 /* X.509 PMI serialNumberAndIssuerSerialCheck
4049
4050 AttributeCertificateExactAssertion     ::= SEQUENCE {
4051    serialNumber              CertificateSerialNumber,
4052    issuer                    AttCertIssuer }
4053
4054 CertificateSerialNumber ::= INTEGER
4055
4056 AttCertIssuer ::=    [0] SEQUENCE {
4057 issuerName                     GeneralNames OPTIONAL,
4058 baseCertificateID         [0] IssuerSerial OPTIONAL,
4059 objectDigestInfo          [1] ObjectDigestInfo OPTIONAL }
4060 -- At least one component shall be present
4061
4062 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
4063
4064 GeneralName ::= CHOICE {
4065   otherName                 [0] INSTANCE OF OTHER-NAME,
4066   rfc822Name                [1] IA5String,
4067   dNSName                   [2] IA5String,
4068   x400Address               [3] ORAddress,
4069   directoryName             [4] Name,
4070   ediPartyName              [5] EDIPartyName,
4071   uniformResourceIdentifier [6] IA5String,
4072   iPAddress                 [7] OCTET STRING,
4073   registeredID              [8] OBJECT IDENTIFIER }
4074
4075 IssuerSerial ::= SEQUENCE {
4076    issuer       GeneralNames,
4077    serial       CertificateSerialNumber,
4078    issuerUID UniqueIdentifier OPTIONAL }
4079
4080 ObjectDigestInfo ::= SEQUENCE {
4081    digestedObjectType ENUMERATED {
4082       publicKey           (0),
4083       publicKeyCert       (1),
4084       otherObjectTypes    (2) },
4085    otherObjectTypeID      OBJECT IDENTIFIER OPTIONAL,
4086    digestAlgorithm        AlgorithmIdentifier,
4087    objectDigest           BIT STRING }
4088
4089  * The way I interpret it, an assertion should look like
4090
4091  { serialNumber 'dd'H,
4092    issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional
4093             baseCertificateID { serial '1d'H,
4094                                 issuer { directoryName:rdnSequence:"cn=zzz" },
4095                                 issuerUID <value>              -- optional
4096                               },                               -- optional
4097             objectDigestInfo { ... }                           -- optional
4098           }
4099  }
4100  
4101  * with issuerName, baseCertificateID and objectDigestInfo optional,
4102  * at least one present; the way it's currently implemented, it is
4103
4104  { serialNumber 'dd'H,
4105    issuer { baseCertificateID { serial '1d'H,
4106                                 issuer { directoryName:rdnSequence:"cn=zzz" }
4107                               }
4108           }
4109  }
4110
4111  * with all the above parts mandatory.
4112  */
4113 static int
4114 serialNumberAndIssuerSerialCheck(
4115         struct berval *in,
4116         struct berval *sn,
4117         struct berval *is,
4118         struct berval *i_sn,    /* contain serial of baseCertificateID */
4119         void *ctx )
4120 {
4121         /* Parse GSER format */ 
4122         enum {
4123                 HAVE_NONE = 0x0,
4124                 HAVE_SN = 0x1,
4125                 HAVE_ISSUER = 0x2,
4126                 HAVE_ALL = ( HAVE_SN | HAVE_ISSUER )
4127         } have = HAVE_NONE, have2 = HAVE_NONE;
4128         int numdquotes = 0;
4129         struct berval x = *in;
4130         struct berval ni;
4131
4132         if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4133
4134         /* no old format */
4135         if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX;
4136
4137         x.bv_val++;
4138         x.bv_len -= 2;
4139
4140         do {
4141
4142                 /* eat leading spaces */
4143                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4144                         /* empty */;
4145                 }
4146
4147                 /* should be at issuer or serialNumber NamedValue */
4148                 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
4149                         if ( have & HAVE_ISSUER ) {
4150                                 return LDAP_INVALID_SYNTAX;
4151                         }
4152
4153                         /* parse IssuerSerial */
4154                         x.bv_val += STRLENOF("issuer");
4155                         x.bv_len -= STRLENOF("issuer");
4156
4157                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4158                         x.bv_val++;
4159                         x.bv_len--;
4160
4161                         /* eat leading spaces */
4162                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4163                                 /* empty */;
4164                         }
4165
4166                         if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4167                         x.bv_val++;
4168                         x.bv_len--;
4169
4170                         /* eat leading spaces */
4171                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4172                                 /* empty */;
4173                         }
4174
4175                         if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) {
4176                                 return LDAP_INVALID_SYNTAX;
4177                         }
4178                         x.bv_val += STRLENOF("baseCertificateID ");
4179                         x.bv_len -= STRLENOF("baseCertificateID ");
4180
4181                         /* eat leading spaces */
4182                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4183                                 /* empty */;
4184                         }
4185
4186                         if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4187                         x.bv_val++;
4188                         x.bv_len--;
4189
4190                         do {
4191                                 /* eat leading spaces */
4192                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4193                                         /* empty */;
4194                                 }
4195
4196                                 /* parse issuer of baseCertificateID */
4197                                 if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) {
4198                                         if ( have2 & HAVE_ISSUER ) {
4199                                                 return LDAP_INVALID_SYNTAX;
4200                                         }
4201
4202                                         x.bv_val += STRLENOF("issuer ");
4203                                         x.bv_len -= STRLENOF("issuer ");
4204
4205                                         /* eat leading spaces */
4206                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4207                                                 /* empty */;
4208                                         }
4209
4210                                         if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4211                                         x.bv_val++;
4212                                         x.bv_len--;
4213
4214                                         /* eat leading spaces */
4215                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4216                                                 /* empty */;
4217                                         }
4218
4219                                         if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) {
4220                                                 return LDAP_INVALID_SYNTAX;
4221                                         }
4222                                         x.bv_val += STRLENOF("directoryName:rdnSequence:");
4223                                         x.bv_len -= STRLENOF("directoryName:rdnSequence:");
4224
4225                                         if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
4226                                         x.bv_val++;
4227                                         x.bv_len--;
4228
4229                                         is->bv_val = x.bv_val;
4230                                         is->bv_len = 0;
4231
4232                                         for ( ; is->bv_len < x.bv_len; ) {
4233                                                 if ( is->bv_val[is->bv_len] != '"' ) {
4234                                                         is->bv_len++;
4235                                                         continue;
4236                                                 }
4237                                                 if ( is->bv_val[is->bv_len + 1] == '"' ) {
4238                                                         /* double dquote */
4239                                                         is->bv_len += 2;
4240                                                         continue;
4241                                                 }
4242                                                 break;
4243                                         }
4244                                         x.bv_val += is->bv_len + 1;
4245                                         x.bv_len -= is->bv_len + 1;
4246
4247                                         /* eat leading spaces */
4248                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4249                                                 /* empty */;
4250                                         }
4251
4252                                         if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4253                                         x.bv_val++;
4254                                         x.bv_len--;
4255
4256                                         have2 |= HAVE_ISSUER;
4257
4258                                 } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) {
4259                                         if ( have2 & HAVE_SN ) {
4260                                                 return LDAP_INVALID_SYNTAX;
4261                                         }
4262
4263                                         x.bv_val += STRLENOF("serial ");
4264                                         x.bv_len -= STRLENOF("serial ");
4265
4266                                         /* eat leading spaces */
4267                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
4268                                                 /* empty */;
4269                                         }
4270
4271                                         if ( checkNum( &x, i_sn ) ) {
4272                                                 return LDAP_INVALID_SYNTAX;
4273                                         }
4274
4275                                         x.bv_val += i_sn->bv_len;
4276                                         x.bv_len -= i_sn->bv_len;
4277
4278                                         have2 |= HAVE_SN;
4279
4280                                 } else {
4281                                         return LDAP_INVALID_SYNTAX;
4282                                 }
4283
4284                                 /* eat leading spaces */
4285                                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4286                                         /* empty */;
4287                                 }
4288
4289                                 if ( have2 == HAVE_ALL ) {
4290                                         break;
4291                                 }
4292
4293                                 if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
4294                                 x.bv_val++;
4295                                 x.bv_len--;
4296                         } while ( 1 );
4297
4298                         if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4299                         x.bv_val++;
4300                         x.bv_len--;
4301
4302                         /* eat leading spaces */
4303                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4304                                 /* empty */;
4305                         }
4306
4307                         if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4308                         x.bv_val++;
4309                         x.bv_len--;
4310
4311                         have |= HAVE_ISSUER;
4312
4313                 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) {
4314                         if ( have & HAVE_SN ) {
4315                                 return LDAP_INVALID_SYNTAX;
4316                         }
4317
4318                         /* parse serialNumber */
4319                         x.bv_val += STRLENOF("serialNumber");
4320                         x.bv_len -= STRLENOF("serialNumber");
4321
4322                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4323                         x.bv_val++;
4324                         x.bv_len--;
4325
4326                         /* eat leading spaces */
4327                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4328                                 /* empty */;
4329                         }
4330                         
4331                         if ( checkNum( &x, sn ) ) {
4332                                 return LDAP_INVALID_SYNTAX;
4333                         }
4334
4335                         x.bv_val += sn->bv_len;
4336                         x.bv_len -= sn->bv_len;
4337
4338                         have |= HAVE_SN;
4339
4340                 } else {
4341                         return LDAP_INVALID_SYNTAX;
4342                 }
4343
4344                 /* eat spaces */
4345                 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4346                         /* empty */;
4347                 }
4348
4349                 if ( have == HAVE_ALL ) {
4350                         break;
4351                 }
4352
4353                 if ( x.bv_val[0] != ',' ) {
4354                         return LDAP_INVALID_SYNTAX;
4355                 }
4356                 x.bv_val++ ;
4357                 x.bv_len--;
4358         } while ( 1 );
4359
4360         /* should have no characters left... */
4361         if( x.bv_len ) return LDAP_INVALID_SYNTAX;
4362
4363         if ( numdquotes == 0 ) {
4364                 ber_dupbv_x( &ni, is, ctx );
4365
4366         } else {
4367                 ber_len_t src, dst;
4368
4369                 ni.bv_len = is->bv_len - numdquotes;
4370                 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
4371                 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
4372                         if ( is->bv_val[src] == '"' ) {
4373                                 src++;
4374                         }
4375                         ni.bv_val[dst] = is->bv_val[src];
4376                 }
4377                 ni.bv_val[dst] = '\0';
4378         }
4379
4380         *is = ni;
4381
4382         /* need to handle double dquotes here */
4383         return 0;
4384 }
4385
4386 /* X.509 PMI serialNumberAndIssuerSerialValidate */
4387 static int
4388 serialNumberAndIssuerSerialValidate(
4389         Syntax *syntax,
4390         struct berval *in )
4391 {
4392         int rc;
4393         struct berval sn, i, i_sn;
4394
4395         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n",
4396                 in->bv_val, 0, 0 );
4397
4398         rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL );
4399         if ( rc ) {
4400                 goto done;
4401         }
4402
4403         /* validate DN -- doesn't handle double dquote */ 
4404         rc = dnValidate( NULL, &i );
4405         if ( rc ) {
4406                 rc = LDAP_INVALID_SYNTAX;
4407         }
4408
4409         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4410                 slap_sl_free( i.bv_val, NULL );
4411         }
4412
4413 done:;
4414         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n",
4415                 in->bv_val, rc, 0 );
4416
4417         return rc;
4418 }
4419
4420 /* X.509 PMI serialNumberAndIssuerSerialPretty */
4421 static int
4422 serialNumberAndIssuerSerialPretty(
4423         Syntax *syntax,
4424         struct berval *in,
4425         struct berval *out,
4426         void *ctx )
4427 {
4428         struct berval sn, i, i_sn, ni = BER_BVNULL;
4429         char *p;
4430         int rc;
4431
4432         assert( in != NULL );
4433         assert( out != NULL );
4434
4435         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n",
4436                 in->bv_val, 0, 0 );
4437
4438         rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4439         if ( rc ) {
4440                 goto done;
4441         }
4442
4443         rc = dnPretty( syntax, &i, &ni, ctx );
4444
4445         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4446                 slap_sl_free( i.bv_val, ctx );
4447         }
4448
4449         if ( rc ) {
4450                 rc = LDAP_INVALID_SYNTAX;
4451                 goto done;
4452         }
4453
4454         /* make room from sn + "$" */
4455         out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }")
4456                 + sn.bv_len + ni.bv_len + i_sn.bv_len;
4457         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4458
4459         if ( out->bv_val == NULL ) {
4460                 out->bv_len = 0;
4461                 rc = LDAP_OTHER;
4462                 goto done;
4463         }
4464
4465         p = out->bv_val;
4466         p = lutil_strcopy( p, "{ serialNumber " );
4467         p = lutil_strncopy( p, sn.bv_val, sn.bv_len );
4468         p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4469         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
4470         p = lutil_strcopy( p, "\" }, serial " );
4471         p = lutil_strncopy( p, i_sn.bv_val, i_sn.bv_len );
4472         p = lutil_strcopy( p, " } } }" );
4473
4474         assert( p == &out->bv_val[out->bv_len] );
4475
4476 done:;
4477         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n",
4478                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4479
4480         slap_sl_free( ni.bv_val, ctx );
4481
4482         return rc; 
4483 }
4484
4485 /* X.509 PMI serialNumberAndIssuerSerialNormalize */
4486 /*
4487  * This routine is called by attributeCertificateExactNormalize
4488  * when attributeCertificateExactNormalize receives a search 
4489  * string instead of a attribute certificate. This routine 
4490  * checks if the search value is valid and then returns the 
4491  * normalized value
4492  */
4493 static int
4494 serialNumberAndIssuerSerialNormalize(
4495         slap_mask_t usage,
4496         Syntax *syntax,
4497         MatchingRule *mr,
4498         struct berval *in,
4499         struct berval *out,
4500         void *ctx )
4501 {
4502         struct berval i, ni = BER_BVNULL,
4503                 sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL,
4504                 i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL;
4505         char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN],
4506                 sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN];
4507         char *p;
4508         int rc;
4509
4510         assert( in != NULL );
4511         assert( out != NULL );
4512
4513         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n",
4514                 in->bv_val, 0, 0 );
4515
4516         rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4517         if ( rc ) {
4518                 goto func_leave;
4519         }
4520
4521         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4522
4523         if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4524                 slap_sl_free( i.bv_val, ctx );
4525         }
4526
4527         if ( rc ) {
4528                 rc = LDAP_INVALID_SYNTAX;
4529                 goto func_leave;
4530         }
4531
4532         /* Convert sn to canonical hex */
4533         sn2.bv_val = sbuf2;
4534         sn2.bv_len = sn.bv_len;
4535         if ( sn.bv_len > sizeof( sbuf2 ) ) {
4536                 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
4537         }
4538         if ( lutil_str2bin( &sn, &sn2, ctx ) ) {
4539                 rc = LDAP_INVALID_SYNTAX;
4540                 goto func_leave;
4541         }
4542
4543         /* Convert i_sn to canonical hex */
4544         i_sn2.bv_val = i_sbuf2;
4545         i_sn2.bv_len = i_sn.bv_len;
4546         if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) {
4547                 i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx );
4548         }
4549         if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) {
4550                 rc = LDAP_INVALID_SYNTAX;
4551                 goto func_leave;
4552         }
4553
4554         sn3.bv_val = sbuf3;
4555         sn3.bv_len = sizeof(sbuf3);
4556         if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
4557                 rc = LDAP_INVALID_SYNTAX;
4558                 goto func_leave;
4559         }
4560
4561         i_sn3.bv_val = i_sbuf3;
4562         i_sn3.bv_len = sizeof(i_sbuf3);
4563         if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) {
4564                 rc = LDAP_INVALID_SYNTAX;
4565                 goto func_leave;
4566         }
4567
4568         out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }")
4569                 + sn3.bv_len + ni.bv_len + i_sn3.bv_len;
4570         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4571
4572         if ( out->bv_val == NULL ) {
4573                 out->bv_len = 0;
4574                 rc = LDAP_OTHER;
4575                 goto func_leave;
4576         }
4577
4578         p = out->bv_val;
4579
4580         p = lutil_strcopy( p, "{ serialNumber " );
4581         p = lutil_strncopy( p, sn3.bv_val, sn3.bv_len );
4582         p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4583         p = lutil_strncopy( p, ni.bv_val, ni.bv_len );
4584         p = lutil_strcopy( p, "\" }, serial " );
4585         p = lutil_strncopy( p, i_sn3.bv_val, i_sn3.bv_len );
4586         p = lutil_strcopy( p, " } } }" );
4587
4588         assert( p == &out->bv_val[out->bv_len] );
4589
4590 func_leave:
4591         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n",
4592                 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4593
4594         if ( sn2.bv_val != sbuf2 ) {
4595                 slap_sl_free( sn2.bv_val, ctx );
4596         }
4597
4598         if ( i_sn2.bv_val != i_sbuf2 ) {
4599                 slap_sl_free( i_sn2.bv_val, ctx );
4600         }
4601
4602         if ( sn3.bv_val != sbuf3 ) {
4603                 slap_sl_free( sn3.bv_val, ctx );
4604         }
4605
4606         if ( i_sn3.bv_val != i_sbuf3 ) {
4607                 slap_sl_free( i_sn3.bv_val, ctx );
4608         }
4609
4610         slap_sl_free( ni.bv_val, ctx );
4611
4612         return rc;
4613 }
4614
4615 /* X.509 PMI attributeCertificateExactNormalize */
4616 static int
4617 attributeCertificateExactNormalize(
4618         slap_mask_t usage,
4619         Syntax *syntax,
4620         MatchingRule *mr,
4621         struct berval *val,
4622         struct berval *normalized,
4623         void *ctx )
4624 {
4625         BerElementBuffer berbuf;
4626         BerElement *ber = (BerElement *)&berbuf;
4627         ber_tag_t tag;
4628         ber_len_t len;
4629         char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN];
4630         struct berval sn, i_sn, sn2, i_sn2;
4631         struct berval issuer_dn = BER_BVNULL, bvdn;
4632         char *p;
4633         int rc = LDAP_INVALID_SYNTAX;
4634
4635         if ( BER_BVISEMPTY( val ) ) {
4636                 goto done;
4637         }
4638
4639         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4640                 return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx );
4641         }
4642
4643         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4644
4645         ber_init2( ber, val, LBER_USE_DER );
4646         tag = ber_skip_tag( ber, &len );        /* Signed Sequence */
4647         tag = ber_skip_tag( ber, &len );        /* Sequence */
4648         tag = ber_skip_tag( ber, &len );        /* (Mandatory) version; must be v2(1) */
4649         ber_skip_data( ber, len );
4650         tag = ber_skip_tag( ber, &len );        /* Holder Sequence */
4651         ber_skip_data( ber, len );
4652
4653         /* Issuer */
4654         tag = ber_skip_tag( ber, &len );        /* Sequence */
4655                                                 /* issuerName (GeneralNames sequence; optional)? */
4656         tag = ber_skip_tag( ber, &len );        /* baseCertificateID (sequence; optional)? */
4657         tag = ber_skip_tag( ber, &len );        /* GeneralNames (sequence) */
4658         tag = ber_skip_tag( ber, &len );        /* directoryName (we only accept this form of GeneralName) */
4659         if ( tag != SLAP_X509_GN_DIRECTORYNAME ) { 
4660                 rc = LDAP_INVALID_SYNTAX; 
4661                 goto done;
4662         }
4663         tag = ber_peek_tag( ber, &len );        /* sequence of RDN */
4664         len = ber_ptrlen( ber );
4665         bvdn.bv_val = val->bv_val + len;
4666         bvdn.bv_len = val->bv_len - len;
4667         rc = dnX509normalize( &bvdn, &issuer_dn );
4668         if ( rc != LDAP_SUCCESS ) goto done;
4669         
4670         tag = ber_skip_tag( ber, &len );        /* sequence of RDN */
4671         ber_skip_data( ber, len ); 
4672         tag = ber_skip_tag( ber, &len );        /* serial number */
4673         if ( tag != LBER_INTEGER ) {
4674                 rc = LDAP_INVALID_SYNTAX; 
4675                 goto done;
4676         }
4677         i_sn.bv_val = (char *)ber->ber_ptr;
4678         i_sn.bv_len = len;
4679         i_sn2.bv_val = issuer_serialbuf;
4680         i_sn2.bv_len = sizeof(issuer_serialbuf);
4681         if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) {
4682                 rc = LDAP_INVALID_SYNTAX;
4683                 goto done;
4684         }
4685         ber_skip_data( ber, len );
4686
4687                                                 /* issuerUID (bitstring; optional)? */
4688                                                 /* objectDigestInfo (sequence; optional)? */
4689
4690         tag = ber_skip_tag( ber, &len );        /* Signature (sequence) */
4691         ber_skip_data( ber, len );
4692         tag = ber_skip_tag( ber, &len );        /* serial number */ 
4693         if ( tag != LBER_INTEGER ) {
4694                 rc = LDAP_INVALID_SYNTAX; 
4695                 goto done;
4696         }
4697         sn.bv_val = (char *)ber->ber_ptr;
4698         sn.bv_len = len;
4699         sn2.bv_val = serialbuf;
4700         sn2.bv_len = sizeof(serialbuf);
4701         if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
4702                 rc = LDAP_INVALID_SYNTAX;
4703                 goto done;
4704         }
4705         ber_skip_data( ber, len );
4706
4707         normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }" )
4708                 + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len;
4709         normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4710
4711         p = normalized->bv_val;
4712
4713         p = lutil_strcopy( p, "{ serialNumber " );
4714         p = lutil_strncopy( p, sn2.bv_val, sn2.bv_len );
4715         p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4716         p = lutil_strncopy( p, issuer_dn.bv_val, issuer_dn.bv_len );
4717         p = lutil_strcopy( p, "\" }, serial " );
4718         p = lutil_strncopy( p, i_sn2.bv_val, i_sn2.bv_len );
4719         p = lutil_strcopy( p, " } } }" );
4720
4721         Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n",
4722                 normalized->bv_val, NULL, NULL );
4723
4724         rc = LDAP_SUCCESS;
4725
4726 done:
4727         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4728         if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx );
4729         if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx );
4730
4731         return rc;
4732 }
4733
4734
4735 static int
4736 hexValidate(
4737         Syntax *syntax,
4738         struct berval *in )
4739 {
4740         ber_len_t       i;
4741
4742         assert( in != NULL );
4743         assert( !BER_BVISNULL( in ) );
4744
4745         for ( i = 0; i < in->bv_len; i++ ) {
4746                 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
4747                         return LDAP_INVALID_SYNTAX;
4748                 }
4749         }
4750
4751         return LDAP_SUCCESS;
4752 }
4753
4754 /* Normalize a SID as used inside a CSN:
4755  * three-digit numeric string */
4756 static int
4757 hexNormalize(
4758         slap_mask_t usage,
4759         Syntax *syntax,
4760         MatchingRule *mr,
4761         struct berval *val,
4762         struct berval *normalized,
4763         void *ctx )
4764 {
4765         ber_len_t       i;
4766
4767         assert( val != NULL );
4768         assert( normalized != NULL );
4769
4770         ber_dupbv_x( normalized, val, ctx );
4771
4772         for ( i = 0; i < normalized->bv_len; i++ ) {
4773                 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
4774                         ber_memfree_x( normalized->bv_val, ctx );
4775                         BER_BVZERO( normalized );
4776                         return LDAP_INVALID_SYNTAX;
4777                 }
4778
4779                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
4780         }
4781
4782         return LDAP_SUCCESS;
4783 }
4784
4785 static int
4786 sidValidate (
4787         Syntax *syntax,
4788         struct berval *in )
4789 {
4790         assert( in != NULL );
4791         assert( !BER_BVISNULL( in ) );
4792
4793         if ( in->bv_len != 3 ) {
4794                 return LDAP_INVALID_SYNTAX;
4795         }
4796
4797         return hexValidate( NULL, in );
4798 }
4799
4800 /* Normalize a SID as used inside a CSN:
4801  * three-digit numeric string */
4802 static int
4803 sidNormalize(
4804         slap_mask_t usage,
4805         Syntax *syntax,
4806         MatchingRule *mr,
4807         struct berval *val,
4808         struct berval *normalized,
4809         void *ctx )
4810 {
4811         if ( val->bv_len != 3 ) {
4812                 return LDAP_INVALID_SYNTAX;
4813         }
4814
4815         return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
4816 }
4817
4818 static int
4819 sidPretty(
4820         Syntax *syntax,
4821         struct berval *val,
4822         struct berval *out,
4823         void *ctx )
4824 {
4825         return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
4826 }
4827
4828 /* Normalize a SID as used inside a CSN, either as-is
4829  * (assertion value) or extracted from the CSN
4830  * (attribute value) */
4831 static int
4832 csnSidNormalize(
4833         slap_mask_t usage,
4834         Syntax *syntax,
4835         MatchingRule *mr,
4836         struct berval *val,
4837         struct berval *normalized,
4838         void *ctx )
4839 {
4840         struct berval   bv;
4841         char            *ptr,
4842                         buf[ 4 ];
4843
4844
4845         if ( BER_BVISEMPTY( val ) ) {
4846                 return LDAP_INVALID_SYNTAX;
4847         }
4848
4849         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4850                 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
4851         }
4852
4853         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4854
4855         ptr = ber_bvchr( val, '#' );
4856         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4857                 return LDAP_INVALID_SYNTAX;
4858         }
4859
4860         bv.bv_val = ptr + 1;
4861         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
4862
4863         ptr = ber_bvchr( &bv, '#' );
4864         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4865                 return LDAP_INVALID_SYNTAX;
4866         }
4867
4868         bv.bv_val = ptr + 1;
4869         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
4870                 
4871         ptr = ber_bvchr( &bv, '#' );
4872         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4873                 return LDAP_INVALID_SYNTAX;
4874         }
4875
4876         bv.bv_len = ptr - bv.bv_val;
4877
4878         if ( bv.bv_len == 2 ) {
4879                 /* OpenLDAP 2.3 SID */
4880                 buf[ 0 ] = '0';
4881                 buf[ 1 ] = bv.bv_val[ 0 ];
4882                 buf[ 2 ] = bv.bv_val[ 1 ];
4883                 buf[ 3 ] = '\0';
4884
4885                 bv.bv_val = buf;
4886                 bv.bv_len = 3;
4887         }
4888
4889         return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
4890 }
4891
4892 static int
4893 csnValidate(
4894         Syntax *syntax,
4895         struct berval *in )
4896 {
4897         struct berval   bv;
4898         char            *ptr;
4899         int             rc;
4900
4901         assert( in != NULL );
4902         assert( !BER_BVISNULL( in ) );
4903
4904         if ( BER_BVISEMPTY( in ) ) {
4905                 return LDAP_INVALID_SYNTAX;
4906         }
4907
4908         bv = *in;
4909
4910         ptr = ber_bvchr( &bv, '#' );
4911         if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) {
4912                 return LDAP_INVALID_SYNTAX;
4913         }
4914
4915         bv.bv_len = ptr - bv.bv_val;
4916         if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
4917                 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
4918         {
4919                 return LDAP_INVALID_SYNTAX;
4920         }
4921
4922         rc = generalizedTimeValidate( NULL, &bv );
4923         if ( rc != LDAP_SUCCESS ) {
4924                 return rc;
4925         }
4926
4927         bv.bv_val = ptr + 1;
4928         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
4929
4930         ptr = ber_bvchr( &bv, '#' );
4931         if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
4932                 return LDAP_INVALID_SYNTAX;
4933         }
4934
4935         bv.bv_len = ptr - bv.bv_val;
4936         if ( bv.bv_len != 6 ) {
4937                 return LDAP_INVALID_SYNTAX;
4938         }
4939
4940         rc = hexValidate( NULL, &bv );
4941         if ( rc != LDAP_SUCCESS ) {
4942                 return rc;
4943         }
4944
4945         bv.bv_val = ptr + 1;
4946         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
4947
4948         ptr = ber_bvchr( &bv, '#' );
4949         if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
4950                 return LDAP_INVALID_SYNTAX;
4951         }
4952
4953         bv.bv_len = ptr - bv.bv_val;
4954         if ( bv.bv_len == 2 ) {
4955                 /* tolerate old 2-digit replica-id */
4956                 rc = hexValidate( NULL, &bv );
4957
4958         } else {
4959                 rc = sidValidate( NULL, &bv );
4960         }
4961         if ( rc != LDAP_SUCCESS ) {
4962                 return rc;
4963         }
4964
4965         bv.bv_val = ptr + 1;
4966         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
4967
4968         if ( bv.bv_len != 6 ) {
4969                 return LDAP_INVALID_SYNTAX;
4970         }
4971
4972         return hexValidate( NULL, &bv );
4973 }
4974
4975 /* Normalize a CSN in OpenLDAP 2.1 format */
4976 static int
4977 csnNormalize21(
4978         slap_mask_t usage,
4979         Syntax *syntax,
4980         MatchingRule *mr,
4981         struct berval *val,
4982         struct berval *normalized,
4983         void *ctx )
4984 {
4985         struct berval   gt, cnt, sid, mod;
4986         struct berval   bv;
4987         char            buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
4988         char            *ptr;
4989         ber_len_t       i;
4990
4991         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
4992         assert( !BER_BVISEMPTY( val ) );
4993
4994         gt = *val;
4995
4996         ptr = ber_bvchr( &gt, '#' );
4997         if ( ptr == NULL || ptr == &gt.bv_val[gt.bv_len] ) {
4998                 return LDAP_INVALID_SYNTAX;
4999         }
5000
5001         gt.bv_len = ptr - gt.bv_val;
5002         if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
5003                 return LDAP_INVALID_SYNTAX;
5004         }
5005
5006         if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
5007                 return LDAP_INVALID_SYNTAX;
5008         }
5009
5010         cnt.bv_val = ptr + 1;
5011         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5012
5013         ptr = ber_bvchr( &cnt, '#' );
5014         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5015                 return LDAP_INVALID_SYNTAX;
5016         }
5017
5018         cnt.bv_len = ptr - cnt.bv_val;
5019         if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
5020                 return LDAP_INVALID_SYNTAX;
5021         }
5022
5023         if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
5024                 return LDAP_INVALID_SYNTAX;
5025         }
5026
5027         cnt.bv_val += STRLENOF( "0x" );
5028         cnt.bv_len -= STRLENOF( "0x" );
5029
5030         sid.bv_val = ptr + 1;
5031         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5032                 
5033         ptr = ber_bvchr( &sid, '#' );
5034         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5035                 return LDAP_INVALID_SYNTAX;
5036         }
5037
5038         sid.bv_len = ptr - sid.bv_val;
5039         if ( sid.bv_len != STRLENOF( "0" ) ) {
5040                 return LDAP_INVALID_SYNTAX;
5041         }
5042
5043         mod.bv_val = ptr + 1;
5044         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5045         if ( mod.bv_len != STRLENOF( "0000" ) ) {
5046                 return LDAP_INVALID_SYNTAX;
5047         }
5048
5049         bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5050         bv.bv_val = buf;
5051
5052         ptr = bv.bv_val;
5053         ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
5054         ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
5055                 STRLENOF( "MM" ) );
5056         ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
5057                 STRLENOF( "SS" ) );
5058         ptr = lutil_strcopy( ptr, ".000000Z#00" );
5059         ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
5060         *ptr++ = '#';
5061         *ptr++ = '0';
5062         *ptr++ = '0';
5063         *ptr++ = sid.bv_val[ 0 ];
5064         *ptr++ = '#';
5065         *ptr++ = '0';
5066         *ptr++ = '0';
5067         for ( i = 0; i < mod.bv_len; i++ ) {
5068                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5069         }
5070         *ptr = '\0';
5071
5072         assert( ptr == &bv.bv_val[bv.bv_len] );
5073
5074         if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5075                 return LDAP_INVALID_SYNTAX;
5076         }
5077
5078         ber_dupbv_x( normalized, &bv, ctx );
5079
5080         return LDAP_SUCCESS;
5081 }
5082
5083 /* Normalize a CSN in OpenLDAP 2.3 format */
5084 static int
5085 csnNormalize23(
5086         slap_mask_t usage,
5087         Syntax *syntax,
5088         MatchingRule *mr,
5089         struct berval *val,
5090         struct berval *normalized,
5091         void *ctx )
5092 {
5093         struct berval   gt, cnt, sid, mod;
5094         struct berval   bv;
5095         char            buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5096         char            *ptr;
5097         ber_len_t       i;
5098
5099         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5100         assert( !BER_BVISEMPTY( val ) );
5101
5102         gt = *val;
5103
5104         ptr = ber_bvchr( &gt, '#' );
5105         if ( ptr == NULL || ptr == &gt.bv_val[gt.bv_len] ) {
5106                 return LDAP_INVALID_SYNTAX;
5107         }
5108
5109         gt.bv_len = ptr - gt.bv_val;
5110         if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
5111                 return LDAP_INVALID_SYNTAX;
5112         }
5113
5114         cnt.bv_val = ptr + 1;
5115         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5116
5117         ptr = ber_bvchr( &cnt, '#' );
5118         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5119                 return LDAP_INVALID_SYNTAX;
5120         }
5121
5122         cnt.bv_len = ptr - cnt.bv_val;
5123         if ( cnt.bv_len != STRLENOF( "000000" ) ) {
5124                 return LDAP_INVALID_SYNTAX;
5125         }
5126
5127         sid.bv_val = ptr + 1;
5128         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5129                 
5130         ptr = ber_bvchr( &sid, '#' );
5131         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5132                 return LDAP_INVALID_SYNTAX;
5133         }
5134
5135         sid.bv_len = ptr - sid.bv_val;
5136         if ( sid.bv_len != STRLENOF( "00" ) ) {
5137                 return LDAP_INVALID_SYNTAX;
5138         }
5139
5140         mod.bv_val = ptr + 1;
5141         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5142         if ( mod.bv_len != STRLENOF( "000000" ) ) {
5143                 return LDAP_INVALID_SYNTAX;
5144         }
5145
5146         bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5147         bv.bv_val = buf;
5148
5149         ptr = bv.bv_val;
5150         ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
5151         ptr = lutil_strcopy( ptr, ".000000Z#" );
5152         ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
5153         *ptr++ = '#';
5154         *ptr++ = '0';
5155         for ( i = 0; i < sid.bv_len; i++ ) {
5156                 *ptr++ = TOLOWER( sid.bv_val[ i ] );
5157         }
5158         *ptr++ = '#';
5159         for ( i = 0; i < mod.bv_len; i++ ) {
5160                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5161         }
5162         *ptr = '\0';
5163
5164         assert( ptr == &bv.bv_val[bv.bv_len] );
5165         if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5166                 return LDAP_INVALID_SYNTAX;
5167         }
5168
5169         ber_dupbv_x( normalized, &bv, ctx );
5170
5171         return LDAP_SUCCESS;
5172 }
5173
5174 /* Normalize a CSN */
5175 static int
5176 csnNormalize(
5177         slap_mask_t usage,
5178         Syntax *syntax,
5179         MatchingRule *mr,
5180         struct berval *val,
5181         struct berval *normalized,
5182         void *ctx )
5183 {
5184         struct berval   cnt, sid, mod;
5185         char            *ptr;
5186         ber_len_t       i;
5187
5188         assert( val != NULL );
5189         assert( normalized != NULL );
5190
5191         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5192
5193         if ( BER_BVISEMPTY( val ) ) {
5194                 return LDAP_INVALID_SYNTAX;
5195         }
5196
5197         if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
5198                 /* Openldap <= 2.3 */
5199
5200                 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
5201         }
5202
5203         if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
5204                 /* Openldap 2.1 */
5205
5206                 return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
5207         }
5208
5209         if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
5210                 return LDAP_INVALID_SYNTAX;
5211         }
5212
5213         ptr = ber_bvchr( val, '#' );
5214         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5215                 return LDAP_INVALID_SYNTAX;
5216         }
5217
5218         if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
5219                 return LDAP_INVALID_SYNTAX;
5220         }
5221
5222         cnt.bv_val = ptr + 1;
5223         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5224
5225         ptr = ber_bvchr( &cnt, '#' );
5226         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5227                 return LDAP_INVALID_SYNTAX;
5228         }
5229
5230         if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
5231                 return LDAP_INVALID_SYNTAX;
5232         }
5233
5234         sid.bv_val = ptr + 1;
5235         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5236                 
5237         ptr = ber_bvchr( &sid, '#' );
5238         if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5239                 return LDAP_INVALID_SYNTAX;
5240         }
5241
5242         sid.bv_len = ptr - sid.bv_val;
5243         if ( sid.bv_len != STRLENOF( "000" ) ) {
5244                 return LDAP_INVALID_SYNTAX;
5245         }
5246
5247         mod.bv_val = ptr + 1;
5248         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5249
5250         if ( mod.bv_len != STRLENOF( "000000" ) ) {
5251                 return LDAP_INVALID_SYNTAX;
5252         }
5253
5254         ber_dupbv_x( normalized, val, ctx );
5255
5256         for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
5257                 i < normalized->bv_len; i++ )
5258         {
5259                 /* assume it's already validated that's all hex digits */
5260                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5261         }
5262
5263         return LDAP_SUCCESS;
5264 }
5265
5266 static int
5267 csnPretty(
5268         Syntax *syntax,
5269         struct berval *val,
5270         struct berval *out,
5271         void *ctx )
5272 {
5273         return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5274 }
5275
5276 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
5277 /* slight optimization - does not need the start parameter */
5278 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
5279 enum { start = 0 };
5280 #endif
5281
5282 static int
5283 check_time_syntax (struct berval *val,
5284         int start,
5285         int *parts,
5286         struct berval *fraction)
5287 {
5288         /*
5289          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
5290          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
5291          * GeneralizedTime supports leap seconds, UTCTime does not.
5292          */
5293         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
5294         static const int mdays[2][12] = {
5295                 /* non-leap years */
5296                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
5297                 /* leap years */
5298                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
5299         };
5300         char *p, *e;
5301         int part, c, c1, c2, tzoffset, leapyear = 0;
5302
5303         p = val->bv_val;
5304         e = p + val->bv_len;
5305
5306 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5307         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
5308 #endif
5309         for (part = start; part < 7 && p < e; part++) {
5310                 c1 = *p;
5311                 if (!ASCII_DIGIT(c1)) {
5312                         break;
5313                 }
5314                 p++;
5315                 if (p == e) {
5316                         return LDAP_INVALID_SYNTAX;
5317                 }
5318                 c = *p++;
5319                 if (!ASCII_DIGIT(c)) {
5320                         return LDAP_INVALID_SYNTAX;
5321                 }
5322                 c += c1 * 10 - '0' * 11;
5323                 if ((part | 1) == 3) {
5324                         --c;
5325                         if (c < 0) {
5326                                 return LDAP_INVALID_SYNTAX;
5327                         }
5328                 }
5329                 if (c >= ceiling[part]) {
5330                         if (! (c == 60 && part == 6 && start == 0))
5331                                 return LDAP_INVALID_SYNTAX;
5332                 }
5333                 parts[part] = c;
5334         }
5335         if (part < 5 + start) {
5336                 return LDAP_INVALID_SYNTAX;
5337         }
5338         for (; part < 9; part++) {
5339                 parts[part] = 0;
5340         }
5341
5342         /* leapyear check for the Gregorian calendar (year>1581) */
5343         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
5344                 leapyear = 1;
5345         }
5346
5347         if (parts[3] >= mdays[leapyear][parts[2]]) {
5348                 return LDAP_INVALID_SYNTAX;
5349         }
5350
5351         if (start == 0) {
5352                 fraction->bv_val = p;
5353                 fraction->bv_len = 0;
5354                 if (p < e && (*p == '.' || *p == ',')) {
5355                         char *end_num;
5356                         while (++p < e && ASCII_DIGIT(*p)) {
5357                                 /* EMTPY */;
5358                         }
5359                         if (p - fraction->bv_val == 1) {
5360                                 return LDAP_INVALID_SYNTAX;
5361                         }
5362                         for (end_num = p; end_num[-1] == '0'; --end_num) {
5363                                 /* EMPTY */;
5364                         }
5365                         c = end_num - fraction->bv_val;
5366                         if (c != 1) fraction->bv_len = c;
5367                 }
5368         }
5369
5370         if (p == e) {
5371                 /* no time zone */
5372                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5373         }
5374
5375         tzoffset = *p++;
5376         switch (tzoffset) {
5377         default:
5378                 return LDAP_INVALID_SYNTAX;
5379         case 'Z':
5380                 /* UTC */
5381                 break;
5382         case '+':
5383         case '-':
5384                 for (part = 7; part < 9 && p < e; part++) {
5385                         c1 = *p;
5386                         if (!ASCII_DIGIT(c1)) {
5387                                 break;
5388                         }
5389                         p++;
5390                         if (p == e) {
5391                                 return LDAP_INVALID_SYNTAX;
5392                         }
5393                         c2 = *p++;
5394                         if (!ASCII_DIGIT(c2)) {
5395                                 return LDAP_INVALID_SYNTAX;
5396                         }
5397                         parts[part] = c1 * 10 + c2 - '0' * 11;
5398                         if (parts[part] >= ceiling[part]) {
5399                                 return LDAP_INVALID_SYNTAX;
5400                         }
5401                 }
5402                 if (part < 8 + start) {
5403                         return LDAP_INVALID_SYNTAX;
5404                 }
5405
5406                 if (tzoffset == '-') {
5407                         /* negative offset to UTC, ie west of Greenwich */
5408                         parts[4] += parts[7];
5409                         parts[5] += parts[8];
5410                         /* offset is just hhmm, no seconds */
5411                         for (part = 6; --part >= 0; ) {
5412                                 if (part != 3) {
5413                                         c = ceiling[part];
5414                                 } else {
5415                                         c = mdays[leapyear][parts[2]];
5416                                 }
5417                                 if (parts[part] >= c) {
5418                                         if (part == 0) {
5419                                                 return LDAP_INVALID_SYNTAX;
5420                                         }
5421                                         parts[part] -= c;
5422                                         parts[part - 1]++;
5423                                         continue;
5424                                 } else if (part != 5) {
5425                                         break;
5426                                 }
5427                         }
5428                 } else {
5429                         /* positive offset to UTC, ie east of Greenwich */
5430                         parts[4] -= parts[7];
5431                         parts[5] -= parts[8];
5432                         for (part = 6; --part >= 0; ) {
5433                                 if (parts[part] < 0) {
5434                                         if (part == 0) {
5435                                                 return LDAP_INVALID_SYNTAX;
5436                                         }
5437                                         if (part != 3) {
5438                                                 c = ceiling[part];
5439                                         } else {
5440                                                 /* make first arg to % non-negative */
5441                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
5442                                         }
5443                                         parts[part] += c;
5444                                         parts[part - 1]--;
5445                                         continue;
5446                                 } else if (part != 5) {
5447                                         break;
5448                                 }
5449                         }
5450                 }
5451         }
5452
5453         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5454 }
5455
5456 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5457
5458 #if 0
5459 static int
5460 xutcTimeNormalize(
5461         Syntax *syntax,
5462         struct berval *val,
5463         struct berval *normalized )
5464 {
5465         int parts[9], rc;
5466
5467         rc = check_time_syntax(val, 1, parts, NULL);
5468         if (rc != LDAP_SUCCESS) {
5469                 return rc;
5470         }
5471
5472         normalized->bv_val = ch_malloc( 14 );
5473         if ( normalized->bv_val == NULL ) {
5474                 return LBER_ERROR_MEMORY;
5475         }
5476
5477         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
5478                 parts[1], parts[2] + 1, parts[3] + 1,
5479                 parts[4], parts[5], parts[6] );
5480         normalized->bv_len = 13;
5481
5482         return LDAP_SUCCESS;
5483 }
5484 #endif /* 0 */
5485
5486 static int
5487 utcTimeValidate(
5488         Syntax *syntax,
5489         struct berval *in )
5490 {
5491         int parts[9];
5492         return check_time_syntax(in, 1, parts, NULL);
5493 }
5494
5495 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
5496
5497 static int
5498 generalizedTimeValidate(
5499         Syntax *syntax,
5500         struct berval *in )
5501 {
5502         int parts[9];
5503         struct berval fraction;
5504         return check_time_syntax(in, 0, parts, &fraction);
5505 }
5506
5507 static int
5508 generalizedTimeNormalize(
5509         slap_mask_t usage,
5510         Syntax *syntax,
5511         MatchingRule *mr,
5512         struct berval *val,
5513         struct berval *normalized,
5514         void *ctx )
5515 {
5516         int parts[9], rc;
5517         unsigned int len;
5518         struct berval fraction;
5519
5520         rc = check_time_syntax(val, 0, parts, &fraction);
5521         if (rc != LDAP_SUCCESS) {
5522                 return rc;
5523         }
5524
5525         len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
5526         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
5527         if ( BER_BVISNULL( normalized ) ) {
5528                 return LBER_ERROR_MEMORY;
5529         }
5530
5531         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
5532                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
5533                 parts[4], parts[5], parts[6] );
5534         if ( !BER_BVISEMPTY( &fraction ) ) {
5535                 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
5536                         fraction.bv_val, fraction.bv_len );
5537                 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
5538         }
5539         strcpy( normalized->bv_val + len-1, "Z" );
5540         normalized->bv_len = len;
5541
5542         return LDAP_SUCCESS;
5543 }
5544
5545 static int
5546 generalizedTimeOrderingMatch(
5547         int *matchp,
5548         slap_mask_t flags,
5549         Syntax *syntax,
5550         MatchingRule *mr,
5551         struct berval *value,
5552         void *assertedValue )
5553 {
5554         struct berval *asserted = (struct berval *) assertedValue;
5555         ber_len_t v_len  = value->bv_len;
5556         ber_len_t av_len = asserted->bv_len;
5557
5558         /* ignore trailing 'Z' when comparing */
5559         int match = memcmp( value->bv_val, asserted->bv_val,
5560                 (v_len < av_len ? v_len : av_len) - 1 );
5561         if ( match == 0 ) match = v_len - av_len;
5562
5563         *matchp = match;
5564         return LDAP_SUCCESS;
5565 }
5566
5567 /* Index generation function */
5568 int generalizedTimeIndexer(
5569         slap_mask_t use,
5570         slap_mask_t flags,
5571         Syntax *syntax,
5572         MatchingRule *mr,
5573         struct berval *prefix,
5574         BerVarray values,
5575         BerVarray *keysp,
5576         void *ctx )
5577 {
5578         int i, j;
5579         BerVarray keys;
5580         char tmp[5];
5581         BerValue bvtmp; /* 40 bit index */
5582         struct lutil_tm tm;
5583         struct lutil_timet tt;
5584
5585         bvtmp.bv_len = sizeof(tmp);
5586         bvtmp.bv_val = tmp;
5587         for( i=0; values[i].bv_val != NULL; i++ ) {
5588                 /* just count them */
5589         }
5590
5591         /* we should have at least one value at this point */
5592         assert( i > 0 );
5593
5594         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
5595
5596         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5597         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
5598                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
5599                 /* Use 40 bits of time for key */
5600                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
5601                         lutil_tm2time( &tm, &tt );
5602                         tmp[0] = tt.tt_gsec & 0xff;
5603                         tmp[4] = tt.tt_sec & 0xff;
5604                         tt.tt_sec >>= 8;
5605                         tmp[3] = tt.tt_sec & 0xff;
5606                         tt.tt_sec >>= 8;
5607                         tmp[2] = tt.tt_sec & 0xff;
5608                         tt.tt_sec >>= 8;
5609                         tmp[1] = tt.tt_sec & 0xff;
5610                         
5611                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
5612                 }
5613         }
5614
5615         keys[j].bv_val = NULL;
5616         keys[j].bv_len = 0;
5617
5618         *keysp = keys;
5619
5620         return LDAP_SUCCESS;
5621 }
5622
5623 /* Index generation function */
5624 int generalizedTimeFilter(
5625         slap_mask_t use,
5626         slap_mask_t flags,
5627         Syntax *syntax,
5628         MatchingRule *mr,
5629         struct berval *prefix,
5630         void * assertedValue,
5631         BerVarray *keysp,
5632         void *ctx )
5633 {
5634         BerVarray keys;
5635         char tmp[5];
5636         BerValue bvtmp; /* 40 bit index */
5637         BerValue *value = (BerValue *) assertedValue;
5638         struct lutil_tm tm;
5639         struct lutil_timet tt;
5640         
5641         bvtmp.bv_len = sizeof(tmp);
5642         bvtmp.bv_val = tmp;
5643         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5644         /* Use 40 bits of time for key */
5645         if ( value->bv_val && value->bv_len >= 10 &&
5646                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
5647
5648                 lutil_tm2time( &tm, &tt );
5649                 tmp[0] = tt.tt_gsec & 0xff;
5650                 tmp[4] = tt.tt_sec & 0xff;
5651                 tt.tt_sec >>= 8;
5652                 tmp[3] = tt.tt_sec & 0xff;
5653                 tt.tt_sec >>= 8;
5654                 tmp[2] = tt.tt_sec & 0xff;
5655                 tt.tt_sec >>= 8;
5656                 tmp[1] = tt.tt_sec & 0xff;
5657
5658                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
5659                 ber_dupbv_x(keys, &bvtmp, ctx );
5660                 keys[1].bv_val = NULL;
5661                 keys[1].bv_len = 0;
5662         } else {
5663                 keys = NULL;
5664         }
5665
5666         *keysp = keys;
5667
5668         return LDAP_SUCCESS;
5669 }
5670
5671 static int
5672 deliveryMethodValidate(
5673         Syntax *syntax,
5674         struct berval *val )
5675 {
5676 #undef LENOF
5677 #define LENOF(s) (sizeof(s)-1)
5678         struct berval tmp = *val;
5679         /*
5680      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
5681          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
5682          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
5683          */
5684 again:
5685         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5686
5687         switch( tmp.bv_val[0] ) {
5688         case 'a':
5689         case 'A':
5690                 if(( tmp.bv_len >= LENOF("any") ) &&
5691                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
5692                 {
5693                         tmp.bv_len -= LENOF("any");
5694                         tmp.bv_val += LENOF("any");
5695                         break;
5696                 }
5697                 return LDAP_INVALID_SYNTAX;
5698
5699         case 'm':
5700         case 'M':
5701                 if(( tmp.bv_len >= LENOF("mhs") ) &&
5702                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
5703                 {
5704                         tmp.bv_len -= LENOF("mhs");
5705                         tmp.bv_val += LENOF("mhs");
5706                         break;
5707                 }
5708                 return LDAP_INVALID_SYNTAX;
5709
5710         case 'p':
5711         case 'P':
5712                 if(( tmp.bv_len >= LENOF("physical") ) &&
5713                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
5714                 {
5715                         tmp.bv_len -= LENOF("physical");
5716                         tmp.bv_val += LENOF("physical");
5717                         break;
5718                 }
5719                 return LDAP_INVALID_SYNTAX;
5720
5721         case 't':
5722         case 'T': /* telex or teletex or telephone */
5723                 if(( tmp.bv_len >= LENOF("telex") ) &&
5724                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
5725                 {
5726                         tmp.bv_len -= LENOF("telex");
5727                         tmp.bv_val += LENOF("telex");
5728                         break;
5729                 }
5730                 if(( tmp.bv_len >= LENOF("teletex") ) &&
5731                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
5732                 {
5733                         tmp.bv_len -= LENOF("teletex");
5734                         tmp.bv_val += LENOF("teletex");
5735                         break;
5736                 }
5737                 if(( tmp.bv_len >= LENOF("telephone") ) &&
5738                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
5739                 {
5740                         tmp.bv_len -= LENOF("telephone");
5741                         tmp.bv_val += LENOF("telephone");
5742                         break;
5743                 }
5744                 return LDAP_INVALID_SYNTAX;
5745
5746         case 'g':
5747         case 'G': /* g3fax or g4fax */
5748                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
5749                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
5750                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
5751                 {
5752                         tmp.bv_len -= LENOF("g3fax");
5753                         tmp.bv_val += LENOF("g3fax");
5754                         break;
5755                 }
5756                 return LDAP_INVALID_SYNTAX;
5757
5758         case 'i':
5759         case 'I':
5760                 if(( tmp.bv_len >= LENOF("ia5") ) &&
5761                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
5762                 {
5763                         tmp.bv_len -= LENOF("ia5");
5764                         tmp.bv_val += LENOF("ia5");
5765                         break;
5766                 }
5767                 return LDAP_INVALID_SYNTAX;
5768
5769         case 'v':
5770         case 'V':
5771                 if(( tmp.bv_len >= LENOF("videotex") ) &&
5772                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
5773                 {
5774                         tmp.bv_len -= LENOF("videotex");
5775                         tmp.bv_val += LENOF("videotex");
5776                         break;
5777                 }
5778                 return LDAP_INVALID_SYNTAX;
5779
5780         default:
5781                 return LDAP_INVALID_SYNTAX;
5782         }
5783
5784         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
5785
5786         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5787                 tmp.bv_len++;
5788                 tmp.bv_val--;
5789         }
5790         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
5791                 tmp.bv_len++;
5792                 tmp.bv_val--;
5793         } else {
5794                 return LDAP_INVALID_SYNTAX;
5795         }
5796         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5797                 tmp.bv_len++;
5798                 tmp.bv_val--;
5799         }
5800
5801         goto again;
5802 }
5803
5804 static int
5805 nisNetgroupTripleValidate(
5806         Syntax *syntax,
5807         struct berval *val )
5808 {
5809         char *p, *e;
5810         int commas = 0;
5811
5812         if ( BER_BVISEMPTY( val ) ) {
5813                 return LDAP_INVALID_SYNTAX;
5814         }
5815
5816         p = (char *)val->bv_val;
5817         e = p + val->bv_len;
5818
5819         if ( *p != '(' /*')'*/ ) {
5820                 return LDAP_INVALID_SYNTAX;
5821         }
5822
5823         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
5824                 if ( *p == ',' ) {
5825                         commas++;
5826                         if ( commas > 2 ) {
5827                                 return LDAP_INVALID_SYNTAX;
5828                         }
5829
5830                 } else if ( !AD_CHAR( *p ) ) {
5831                         return LDAP_INVALID_SYNTAX;
5832                 }
5833         }
5834
5835         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
5836                 return LDAP_INVALID_SYNTAX;
5837         }
5838
5839         p++;
5840
5841         if (p != e) {
5842                 return LDAP_INVALID_SYNTAX;
5843         }
5844
5845         return LDAP_SUCCESS;
5846 }
5847
5848 static int
5849 bootParameterValidate(
5850         Syntax *syntax,
5851         struct berval *val )
5852 {
5853         char *p, *e;
5854
5855         if ( BER_BVISEMPTY( val ) ) {
5856                 return LDAP_INVALID_SYNTAX;
5857         }
5858
5859         p = (char *)val->bv_val;
5860         e = p + val->bv_len;
5861
5862         /* key */
5863         for (; ( p < e ) && ( *p != '=' ); p++ ) {
5864                 if ( !AD_CHAR( *p ) ) {
5865                         return LDAP_INVALID_SYNTAX;
5866                 }
5867         }
5868
5869         if ( *p != '=' ) {
5870                 return LDAP_INVALID_SYNTAX;
5871         }
5872
5873         /* server */
5874         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
5875                 if ( !AD_CHAR( *p ) ) {
5876                         return LDAP_INVALID_SYNTAX;
5877                 }
5878         }
5879
5880         if ( *p != ':' ) {
5881                 return LDAP_INVALID_SYNTAX;
5882         }
5883
5884         /* path */
5885         for ( p++; p < e; p++ ) {
5886                 if ( !SLAP_PRINTABLE( *p ) ) {
5887                         return LDAP_INVALID_SYNTAX;
5888                 }
5889         }
5890
5891         return LDAP_SUCCESS;
5892 }
5893
5894 static int
5895 firstComponentNormalize(
5896         slap_mask_t usage,
5897         Syntax *syntax,
5898         MatchingRule *mr,
5899         struct berval *val,
5900         struct berval *normalized,
5901         void *ctx )
5902 {
5903         int rc;
5904         struct berval comp;
5905         ber_len_t len;
5906
5907         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
5908                 ber_dupbv_x( normalized, val, ctx );
5909                 return LDAP_SUCCESS;
5910         }
5911
5912         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5913
5914         if( ! ( val->bv_val[0] == '(' /*')'*/
5915                         && val->bv_val[val->bv_len - 1] == /*'('*/ ')' )
5916                 && ! ( val->bv_val[0] == '{' /*'}'*/
5917                         && val->bv_val[val->bv_len - 1] == /*'('*/ '}' ) )
5918         {
5919                 return LDAP_INVALID_SYNTAX;
5920         }
5921
5922         /* trim leading white space */
5923         for( len=1;
5924                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
5925                 len++ )
5926         {
5927                 /* empty */
5928         }
5929
5930         /* grab next word */
5931         comp.bv_val = &val->bv_val[len];
5932         len = val->bv_len - len - STRLENOF(/*"{"*/ "}");
5933         for( comp.bv_len = 0;
5934                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
5935                 comp.bv_len++ )
5936         {
5937                 /* empty */
5938         }
5939
5940         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
5941                 rc = numericoidValidate( NULL, &comp );
5942         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
5943                 rc = integerValidate( NULL, &comp );
5944         } else {
5945                 rc = LDAP_INVALID_SYNTAX;
5946         }
5947         
5948
5949         if( rc == LDAP_SUCCESS ) {
5950                 ber_dupbv_x( normalized, &comp, ctx );
5951         }
5952
5953         return rc;
5954 }
5955
5956 static char *country_gen_syn[] = {
5957         "1.3.6.1.4.1.1466.115.121.1.15",
5958         "1.3.6.1.4.1.1466.115.121.1.26",
5959         "1.3.6.1.4.1.1466.115.121.1.44",
5960         NULL
5961 };
5962
5963 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
5964 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
5965
5966 static slap_syntax_defs_rec syntax_defs[] = {
5967         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
5968                 X_BINARY X_NOT_H_R ")",
5969                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
5970         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
5971                 0, NULL, NULL, NULL},
5972         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
5973                 0, NULL, NULL, NULL},
5974         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
5975                 X_NOT_H_R ")",
5976                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
5977         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
5978                 X_NOT_H_R ")",
5979                 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
5980         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
5981                 0, NULL, bitStringValidate, NULL },
5982         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
5983                 0, NULL, booleanValidate, NULL},
5984         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
5985                 X_BINARY X_NOT_H_R ")",
5986                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
5987                 NULL, certificateValidate, NULL},
5988         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
5989                 X_BINARY X_NOT_H_R ")",
5990                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
5991                 NULL, certificateListValidate, NULL},
5992         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
5993                 X_BINARY X_NOT_H_R ")",
5994                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
5995                 NULL, sequenceValidate, NULL},
5996         {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' "
5997                 X_BINARY X_NOT_H_R ")",
5998                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
5999                 NULL, attributeCertificateValidate, NULL},
6000 #if 0   /* need to go __after__ printableString */
6001         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6002                 0, "1.3.6.1.4.1.1466.115.121.1.44",
6003                 countryStringValidate, NULL},
6004 #endif
6005         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
6006                 0, NULL, dnValidate, dnPretty},
6007         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
6008                 0, NULL, rdnValidate, rdnPretty},
6009 #ifdef LDAP_COMP_MATCH
6010         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
6011                 0, NULL, allComponentsValidate, NULL},
6012         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
6013                 0, NULL, componentFilterValidate, NULL},
6014 #endif
6015         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
6016                 0, NULL, NULL, NULL},
6017         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
6018                 0, NULL, deliveryMethodValidate, NULL},
6019         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
6020                 0, NULL, UTF8StringValidate, NULL},
6021         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
6022                 0, NULL, NULL, NULL},
6023         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
6024                 0, NULL, NULL, NULL},
6025         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
6026                 0, NULL, NULL, NULL},
6027         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
6028                 0, NULL, NULL, NULL},
6029         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
6030                 0, NULL, NULL, NULL},
6031         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
6032                 0, NULL, printablesStringValidate, NULL},
6033         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
6034                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
6035         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
6036                 0, NULL, generalizedTimeValidate, NULL},
6037         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
6038                 0, NULL, NULL, NULL},
6039         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
6040                 0, NULL, IA5StringValidate, NULL},
6041         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
6042                 0, NULL, integerValidate, NULL},
6043         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
6044                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6045         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
6046                 0, NULL, NULL, NULL},
6047         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
6048                 0, NULL, NULL, NULL},
6049         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
6050                 0, NULL, NULL, NULL},
6051         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
6052                 0, NULL, NULL, NULL},
6053         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
6054                 0, NULL, NULL, NULL},
6055         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
6056                 0, NULL, nameUIDValidate, nameUIDPretty },
6057         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
6058                 0, NULL, NULL, NULL},
6059         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
6060                 0, NULL, numericStringValidate, NULL},
6061         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
6062                 0, NULL, NULL, NULL},
6063         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
6064                 0, NULL, numericoidValidate, NULL},
6065         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
6066                 0, NULL, IA5StringValidate, NULL},
6067         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
6068                 0, NULL, blobValidate, NULL},
6069         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
6070                 0, NULL, postalAddressValidate, NULL},
6071         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
6072                 0, NULL, NULL, NULL},
6073         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
6074                 0, NULL, NULL, NULL},
6075         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
6076                 0, NULL, printableStringValidate, NULL},
6077         /* moved here because now depends on Directory String, IA5 String 
6078          * and Printable String */
6079         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6080                 0, country_gen_syn, countryStringValidate, NULL},
6081         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
6082 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
6083                 0, NULL, subtreeSpecificationValidate, NULL},
6084         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
6085                 X_BINARY X_NOT_H_R ")",
6086                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6087         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
6088                 0, NULL, printableStringValidate, NULL},
6089         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
6090                 0, NULL, NULL, NULL},
6091         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
6092                 0, NULL, printablesStringValidate, NULL},
6093 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
6094         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
6095                 0, NULL, utcTimeValidate, NULL},
6096 #endif
6097         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
6098                 0, NULL, NULL, NULL},
6099         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
6100                 0, NULL, NULL, NULL},
6101         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
6102                 0, NULL, NULL, NULL},
6103         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
6104                 0, NULL, NULL, NULL},
6105         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
6106                 0, NULL, NULL, NULL},
6107
6108         /* RFC 2307 NIS Syntaxes */
6109         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
6110                 0, NULL, nisNetgroupTripleValidate, NULL},
6111         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
6112                 0, NULL, bootParameterValidate, NULL},
6113
6114         /* draft-zeilenga-ldap-x509 */
6115         {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
6116                 SLAP_SYNTAX_HIDE, NULL,
6117                 serialNumberAndIssuerValidate,
6118                 serialNumberAndIssuerPretty},
6119         {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
6120                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6121         {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
6122                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6123         {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
6124                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6125         {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
6126                 SLAP_SYNTAX_HIDE, NULL,
6127                 issuerAndThisUpdateValidate,
6128                 issuerAndThisUpdatePretty},
6129         {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
6130                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6131         {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
6132                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6133         {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )",
6134                 SLAP_SYNTAX_HIDE, NULL,
6135                 serialNumberAndIssuerSerialValidate,
6136                 serialNumberAndIssuerSerialPretty},
6137         {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )",
6138                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6139
6140 #ifdef SLAPD_AUTHPASSWD
6141         /* needs updating */
6142         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
6143                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6144 #endif
6145
6146         {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
6147                 0, NULL, UUIDValidate, UUIDPretty},
6148
6149         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
6150                 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
6151
6152         {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
6153                 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
6154
6155         /* OpenLDAP Void Syntax */
6156         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
6157                 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
6158
6159         /* FIXME: OID is unused, but not registered yet */
6160         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
6161                 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
6162
6163         {NULL, 0, NULL, NULL, NULL}
6164 };
6165
6166 char *csnSIDMatchSyntaxes[] = {
6167         "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
6168         NULL
6169 };
6170 char *certificateExactMatchSyntaxes[] = {
6171         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6172         NULL
6173 };
6174 char *certificateListExactMatchSyntaxes[] = {
6175         "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6176         NULL
6177 };
6178 char *attributeCertificateExactMatchSyntaxes[] = {
6179         attributeCertificateSyntaxOID  /* attributeCertificate */,
6180         NULL
6181 };
6182
6183 #ifdef LDAP_COMP_MATCH
6184 char *componentFilterMatchSyntaxes[] = {
6185         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6186         "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6187         attributeCertificateSyntaxOID /* attributeCertificate */,
6188         NULL
6189 };
6190 #endif
6191
6192 char *directoryStringSyntaxes[] = {
6193         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
6194         NULL
6195 };
6196 char *integerFirstComponentMatchSyntaxes[] = {
6197         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
6198         "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
6199         NULL
6200 };
6201 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
6202         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
6203         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
6204         "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
6205         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
6206         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
6207         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
6208         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
6209         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
6210         NULL
6211 };
6212
6213 /*
6214  * Other matching rules in X.520 that we do not use (yet):
6215  *
6216  * 2.5.13.25    uTCTimeMatch
6217  * 2.5.13.26    uTCTimeOrderingMatch
6218  * 2.5.13.31*   directoryStringFirstComponentMatch
6219  * 2.5.13.32*   wordMatch
6220  * 2.5.13.33*   keywordMatch
6221  * 2.5.13.36+   certificatePairExactMatch
6222  * 2.5.13.37+   certificatePairMatch
6223  * 2.5.13.40+   algorithmIdentifierMatch
6224  * 2.5.13.41*   storedPrefixMatch
6225  * 2.5.13.42    attributeCertificateMatch
6226  * 2.5.13.43    readerAndKeyIDMatch
6227  * 2.5.13.44    attributeIntegrityMatch
6228  *
6229  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
6230  * (+) described in draft-zeilenga-ldap-x509
6231  */
6232 static slap_mrule_defs_rec mrule_defs[] = {
6233         /*
6234          * EQUALITY matching rules must be listed after associated APPROX
6235          * matching rules.  So, we list all APPROX matching rules first.
6236          */
6237         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
6238                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6239                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6240                 NULL, NULL, directoryStringApproxMatch,
6241                 directoryStringApproxIndexer, directoryStringApproxFilter,
6242                 NULL},
6243
6244         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
6245                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6246                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6247                 NULL, NULL, IA5StringApproxMatch,
6248                 IA5StringApproxIndexer, IA5StringApproxFilter,
6249                 NULL},
6250
6251         /*
6252          * Other matching rules
6253          */
6254         
6255         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
6256                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
6257                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6258                 NULL, NULL, octetStringMatch,
6259                 octetStringIndexer, octetStringFilter,
6260                 NULL },
6261
6262         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
6263                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6264                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6265                 NULL, dnNormalize, dnMatch,
6266                 octetStringIndexer, octetStringFilter,
6267                 NULL },
6268
6269         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
6270                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6271                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6272                 NULL, dnNormalize, dnRelativeMatch,
6273                 NULL, NULL,
6274                 NULL },
6275
6276         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
6277                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6278                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6279                 NULL, dnNormalize, dnRelativeMatch,
6280                 NULL, NULL,
6281                 NULL },
6282
6283         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
6284                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6285                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6286                 NULL, dnNormalize, dnRelativeMatch,
6287                 NULL, NULL,
6288                 NULL },
6289
6290         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
6291                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6292                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6293                 NULL, dnNormalize, dnRelativeMatch,
6294                 NULL, NULL,
6295                 NULL },
6296
6297         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
6298                 "SYNTAX 1.2.36.79672281.1.5.0 )",
6299                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6300                 NULL, rdnNormalize, rdnMatch,
6301                 octetStringIndexer, octetStringFilter,
6302                 NULL },
6303
6304 #ifdef LDAP_COMP_MATCH
6305         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
6306                 "SYNTAX 1.2.36.79672281.1.5.2 )",
6307                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
6308                 NULL, NULL , componentFilterMatch,
6309                 octetStringIndexer, octetStringFilter,
6310                 NULL },
6311
6312         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
6313                 "SYNTAX 1.2.36.79672281.1.5.3 )",
6314                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6315                 NULL, NULL , allComponentsMatch,
6316                 octetStringIndexer, octetStringFilter,
6317                 NULL },
6318
6319         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
6320                 "SYNTAX 1.2.36.79672281.1.5.3 )",
6321                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6322                 NULL, NULL , directoryComponentsMatch,
6323                 octetStringIndexer, octetStringFilter,
6324                 NULL },
6325 #endif
6326
6327         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
6328                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6329                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6330                 NULL, UTF8StringNormalize, octetStringMatch,
6331                 octetStringIndexer, octetStringFilter,
6332                 directoryStringApproxMatchOID },
6333
6334         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
6335                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6336                 SLAP_MR_ORDERING, directoryStringSyntaxes,
6337                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6338                 NULL, NULL,
6339                 "caseIgnoreMatch" },
6340
6341         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
6342                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
6343                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6344                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6345                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6346                 "caseIgnoreMatch" },
6347
6348         {"( 2.5.13.5 NAME 'caseExactMatch' "
6349                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6350                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6351                 NULL, UTF8StringNormalize, octetStringMatch,
6352                 octetStringIndexer, octetStringFilter,
6353                 directoryStringApproxMatchOID },
6354
6355         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
6356                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6357                 SLAP_MR_ORDERING, directoryStringSyntaxes,
6358                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6359                 NULL, NULL,
6360                 "caseExactMatch" },
6361
6362         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
6363                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
6364                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6365                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6366                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6367                 "caseExactMatch" },
6368
6369         {"( 2.5.13.8 NAME 'numericStringMatch' "
6370                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6371                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6372                 NULL, numericStringNormalize, octetStringMatch,
6373                 octetStringIndexer, octetStringFilter,
6374                 NULL },
6375
6376         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
6377                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6378                 SLAP_MR_ORDERING, NULL,
6379                 NULL, numericStringNormalize, octetStringOrderingMatch,
6380                 NULL, NULL,
6381                 "numericStringMatch" },
6382
6383         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
6384                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
6385                 SLAP_MR_SUBSTR, NULL,
6386                 NULL, numericStringNormalize, octetStringSubstringsMatch,
6387                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6388                 "numericStringMatch" },
6389
6390         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
6391                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
6392                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6393                 NULL, postalAddressNormalize, octetStringMatch,
6394                 octetStringIndexer, octetStringFilter,
6395                 NULL },
6396
6397         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
6398                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
6399                 SLAP_MR_SUBSTR, NULL,
6400                 NULL, NULL, NULL, NULL, NULL,
6401                 "caseIgnoreListMatch" },
6402
6403         {"( 2.5.13.13 NAME 'booleanMatch' "
6404                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
6405                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6406                 NULL, NULL, booleanMatch,
6407                 octetStringIndexer, octetStringFilter,
6408                 NULL },
6409
6410         {"( 2.5.13.14 NAME 'integerMatch' "
6411                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6412                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6413                 NULL, NULL, integerMatch,
6414                 integerIndexer, integerFilter,
6415                 NULL },
6416
6417         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
6418                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6419                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
6420                 NULL, NULL, integerMatch,
6421                 NULL, NULL,
6422                 "integerMatch" },
6423
6424         {"( 2.5.13.16 NAME 'bitStringMatch' "
6425                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
6426                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6427                 NULL, NULL, octetStringMatch,
6428                 octetStringIndexer, octetStringFilter,
6429                 NULL },
6430
6431         {"( 2.5.13.17 NAME 'octetStringMatch' "
6432                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6433                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6434                 NULL, NULL, octetStringMatch,
6435                 octetStringIndexer, octetStringFilter,
6436                 NULL },
6437
6438         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
6439                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6440                 SLAP_MR_ORDERING, NULL,
6441                 NULL, NULL, octetStringOrderingMatch,
6442                 NULL, NULL,
6443                 "octetStringMatch" },
6444
6445         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
6446                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6447                 SLAP_MR_SUBSTR, NULL,
6448                 NULL, NULL, octetStringSubstringsMatch,
6449                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6450                 "octetStringMatch" },
6451
6452         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
6453                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
6454                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6455                 NULL,
6456                 telephoneNumberNormalize, octetStringMatch,
6457                 octetStringIndexer, octetStringFilter,
6458                 NULL },
6459
6460         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
6461                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
6462                 SLAP_MR_SUBSTR, NULL,
6463                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
6464                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6465                 "telephoneNumberMatch" },
6466
6467         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
6468                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
6469                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6470                 NULL, NULL, NULL, NULL, NULL, NULL },
6471
6472         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
6473                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
6474                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6475                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
6476                 uniqueMemberIndexer, uniqueMemberFilter,
6477                 NULL },
6478
6479         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
6480                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
6481                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6482                 NULL, NULL, NULL, NULL, NULL, NULL },
6483
6484         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
6485                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6486                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6487                 NULL, generalizedTimeNormalize, octetStringMatch,
6488                 generalizedTimeIndexer, generalizedTimeFilter,
6489                 NULL },
6490
6491         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
6492                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6493                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
6494                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
6495                 NULL, NULL,
6496                 "generalizedTimeMatch" },
6497
6498         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
6499                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6500                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6501                         integerFirstComponentMatchSyntaxes,
6502                 NULL, firstComponentNormalize, integerMatch,
6503                 octetStringIndexer, octetStringFilter,
6504                 NULL },
6505
6506         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
6507                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
6508                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6509                         objectIdentifierFirstComponentMatchSyntaxes,
6510                 NULL, firstComponentNormalize, octetStringMatch,
6511                 octetStringIndexer, octetStringFilter,
6512                 NULL },
6513
6514         {"( 2.5.13.34 NAME 'certificateExactMatch' "
6515                 "SYNTAX 1.3.6.1.1.15.1 )",
6516                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
6517                 NULL, certificateExactNormalize, octetStringMatch,
6518                 octetStringIndexer, octetStringFilter,
6519                 NULL },
6520
6521         {"( 2.5.13.35 NAME 'certificateMatch' "
6522                 "SYNTAX 1.3.6.1.1.15.2 )",
6523                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6524                 NULL, NULL, NULL, NULL, NULL,
6525                 NULL },
6526
6527         {"( 2.5.13.38 NAME 'certificateListExactMatch' "
6528                 "SYNTAX 1.3.6.1.1.15.5 )",
6529                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes,
6530                 NULL, certificateListExactNormalize, octetStringMatch,
6531                 octetStringIndexer, octetStringFilter,
6532                 NULL },
6533
6534         {"( 2.5.13.39 NAME 'certificateListMatch' "
6535                 "SYNTAX 1.3.6.1.1.15.6 )",
6536                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6537                 NULL, NULL, NULL, NULL, NULL,
6538                 NULL },
6539
6540         {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' "
6541                 "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )",
6542                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes,
6543                 NULL, attributeCertificateExactNormalize, octetStringMatch,
6544                 octetStringIndexer, octetStringFilter,
6545                 NULL },
6546
6547         {"( 2.5.13.46 NAME 'attributeCertificateMatch' "
6548                 "SYNTAX " attributeCertificateAssertionSyntaxOID " )",
6549                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL,
6550                 NULL, NULL, NULL, NULL, NULL,
6551                 NULL },
6552
6553         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
6554                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6555                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6556                 NULL, IA5StringNormalize, octetStringMatch,
6557                 octetStringIndexer, octetStringFilter,
6558                 IA5StringApproxMatchOID },
6559
6560         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
6561                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6562                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6563                 NULL, IA5StringNormalize, octetStringMatch,
6564                 octetStringIndexer, octetStringFilter,
6565                 IA5StringApproxMatchOID },
6566
6567         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
6568                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6569                 SLAP_MR_SUBSTR, NULL,
6570                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6571                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6572                 "caseIgnoreIA5Match" },
6573
6574         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
6575                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6576                 SLAP_MR_SUBSTR, NULL,
6577                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6578                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6579                 "caseExactIA5Match" },
6580
6581 #ifdef SLAPD_AUTHPASSWD
6582         /* needs updating */
6583         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
6584                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6585                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6586                 NULL, NULL, authPasswordMatch,
6587                 NULL, NULL,
6588                 NULL},
6589 #endif
6590
6591         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
6592                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6593                 SLAP_MR_EXT, NULL,
6594                 NULL, NULL, integerBitAndMatch,
6595                 NULL, NULL,
6596                 "integerMatch" },
6597
6598         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
6599                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6600                 SLAP_MR_EXT, NULL,
6601                 NULL, NULL, integerBitOrMatch,
6602                 NULL, NULL,
6603                 "integerMatch" },
6604
6605         {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
6606                 "SYNTAX 1.3.6.1.1.16.1 )",
6607                 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
6608                 NULL, UUIDNormalize, octetStringMatch,
6609                 octetStringIndexer, octetStringFilter,
6610                 NULL},
6611
6612         {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
6613                 "SYNTAX 1.3.6.1.1.16.1 )",
6614                 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
6615                 NULL, UUIDNormalize, octetStringOrderingMatch,
6616                 octetStringIndexer, octetStringFilter,
6617                 "UUIDMatch"},
6618
6619         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
6620                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6621                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
6622                 NULL, csnNormalize, csnMatch,
6623                 csnIndexer, csnFilter,
6624                 NULL},
6625
6626         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
6627                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6628                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
6629                 NULL, csnNormalize, csnOrderingMatch,
6630                 NULL, NULL,
6631                 "CSNMatch" },
6632
6633         {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
6634                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
6635                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
6636                 NULL, csnSidNormalize, octetStringMatch,
6637                 octetStringIndexer, octetStringFilter,
6638                 NULL },
6639
6640         /* FIXME: OID is unused, but not registered yet */
6641         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
6642                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
6643                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6644                 NULL, authzNormalize, authzMatch,
6645                 NULL, NULL,
6646                 NULL},
6647
6648         {NULL, SLAP_MR_NONE, NULL,
6649                 NULL, NULL, NULL, NULL, NULL,
6650                 NULL }
6651 };
6652
6653 int
6654 slap_schema_init( void )
6655 {
6656         int             res;
6657         int             i;
6658
6659         /* we should only be called once (from main) */
6660         assert( schema_init_done == 0 );
6661
6662         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
6663                 res = register_syntax( &syntax_defs[i] );
6664
6665                 if ( res ) {
6666                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
6667                                  syntax_defs[i].sd_desc );
6668                         return LDAP_OTHER;
6669                 }
6670         }
6671
6672         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
6673                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
6674                         mrule_defs[i].mrd_compat_syntaxes == NULL )
6675                 {
6676                         fprintf( stderr,
6677                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
6678                                  mrule_defs[i].mrd_desc );
6679                         continue;
6680                 }
6681
6682                 res = register_matching_rule( &mrule_defs[i] );
6683
6684                 if ( res ) {
6685                         fprintf( stderr,
6686                                 "slap_schema_init: Error registering matching rule %s\n",
6687                                  mrule_defs[i].mrd_desc );
6688                         return LDAP_OTHER;
6689                 }
6690         }
6691
6692         res = slap_schema_load();
6693         schema_init_done = 1;
6694         return res;
6695 }
6696
6697 void
6698 schema_destroy( void )
6699 {
6700         oidm_destroy();
6701         oc_destroy();
6702         at_destroy();
6703         mr_destroy();
6704         mru_destroy();
6705         syn_destroy();
6706
6707         if( schema_init_done ) {
6708                 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
6709                 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
6710         }
6711 }