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