]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
6bdd95cf7576c77052dd6d45119eabe09afbea9e
[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-2007 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 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
61 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
62 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
63 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
64
65 /* Default to no ordered integer indexing */
66 unsigned int index_intlen = 0;
67
68 ldap_pvt_thread_mutex_t ad_undef_mutex;
69 ldap_pvt_thread_mutex_t oc_undef_mutex;
70
71 static int
72 generalizedTimeValidate(
73         Syntax *syntax,
74         struct berval *in );
75
76 static int
77 inValidate(
78         Syntax *syntax,
79         struct berval *in )
80 {
81         /* no value allowed */
82         return LDAP_INVALID_SYNTAX;
83 }
84
85 static int
86 blobValidate(
87         Syntax *syntax,
88         struct berval *in )
89 {
90         /* any value allowed */
91         return LDAP_SUCCESS;
92 }
93
94 #define berValidate blobValidate
95
96 static int
97 sequenceValidate(
98         Syntax *syntax,
99         struct berval *in )
100 {
101         if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
102         if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
103
104         return LDAP_SUCCESS;
105 }
106
107 /* X.509 related stuff */
108
109 enum {
110         SLAP_X509_V1            = 0,
111         SLAP_X509_V2            = 1,
112         SLAP_X509_V3            = 2
113 };
114
115 #define SLAP_X509_OPTION        (LBER_CLASS_CONTEXT|LBER_CONSTRUCTED)
116
117 enum {
118         SLAP_X509_OPT_C_VERSION         = SLAP_X509_OPTION + 0,
119         SLAP_X509_OPT_C_ISSUERUNIQUEID  = SLAP_X509_OPTION + 1,
120         SLAP_X509_OPT_C_SUBJECTUNIQUEID = SLAP_X509_OPTION + 2,
121         SLAP_X509_OPT_C_EXTENSIONS      = SLAP_X509_OPTION + 3
122 };
123
124 enum {
125         SLAP_X509_OPT_CL_CRLEXTENSIONS  = SLAP_X509_OPTION + 0
126 };
127
128 /* X.509 certificate validation */
129 static int certificateValidate( Syntax *syntax, struct berval *in )
130 {
131         BerElementBuffer berbuf;
132         BerElement *ber = (BerElement *)&berbuf;
133         ber_tag_t tag;
134         ber_len_t len;
135         ber_int_t version = SLAP_X509_V1;
136
137         ber_init2( ber, in, LBER_USE_DER );
138         tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
139         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
140         tag = ber_skip_tag( ber, &len );        /* Sequence */
141         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
142         tag = ber_peek_tag( ber, &len );
143         /* Optional version */
144         if ( tag == SLAP_X509_OPT_C_VERSION ) {
145                 tag = ber_skip_tag( ber, &len );
146                 tag = ber_get_int( ber, &version );
147                 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
148         }
149         /* NOTE: don't try to parse Serial, because it might be longer
150          * than sizeof(ber_int_t); deferred to certificateExactNormalize() */
151         tag = ber_skip_tag( ber, &len );        /* Serial */
152         if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
153         ber_skip_data( ber, len );
154         tag = ber_skip_tag( ber, &len );        /* Signature Algorithm */
155         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
156         ber_skip_data( ber, len );
157         tag = ber_skip_tag( ber, &len );        /* Issuer DN */
158         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
159         ber_skip_data( ber, len );
160         tag = ber_skip_tag( ber, &len );        /* Validity */
161         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
162         ber_skip_data( ber, len );
163         tag = ber_skip_tag( ber, &len );        /* Subject DN */
164         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
165         ber_skip_data( ber, len );
166         tag = ber_skip_tag( ber, &len );        /* Subject PublicKeyInfo */
167         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
168         ber_skip_data( ber, len );
169         tag = ber_skip_tag( ber, &len );
170         if ( tag == SLAP_X509_OPT_C_ISSUERUNIQUEID ) {  /* issuerUniqueID */
171                 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
172                 ber_skip_data( ber, len );
173                 tag = ber_skip_tag( ber, &len );
174         }
175         if ( tag == SLAP_X509_OPT_C_SUBJECTUNIQUEID ) { /* subjectUniqueID */
176                 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
177                 ber_skip_data( ber, len );
178                 tag = ber_skip_tag( ber, &len );
179         }
180         if ( tag == SLAP_X509_OPT_C_EXTENSIONS ) {      /* Extensions */
181                 if ( version < SLAP_X509_V3 ) return LDAP_INVALID_SYNTAX;
182                 tag = ber_skip_tag( ber, &len );
183                 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
184                 ber_skip_data( ber, len );
185                 tag = ber_skip_tag( ber, &len );
186         }
187         /* signatureAlgorithm */
188         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
189         ber_skip_data( ber, len );
190         tag = ber_skip_tag( ber, &len );
191         /* Signature */
192         if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX; 
193         ber_skip_data( ber, len );
194         tag = ber_skip_tag( ber, &len );
195         /* Must be at end now */
196         if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
197         return LDAP_SUCCESS;
198 }
199
200 /* X.509 certificate list validation */
201 static int certificateListValidate( Syntax *syntax, struct berval *in )
202 {
203         BerElementBuffer berbuf;
204         BerElement *ber = (BerElement *)&berbuf;
205         ber_tag_t tag;
206         ber_len_t len;
207         ber_int_t version = SLAP_X509_V1;
208
209         ber_init2( ber, in, LBER_USE_DER );
210         tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
211         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
212         tag = ber_skip_tag( ber, &len );        /* Sequence */
213         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
214         tag = ber_peek_tag( ber, &len );
215         /* Optional version */
216         if ( tag == LBER_INTEGER ) {
217                 tag = ber_get_int( ber, &version );
218                 assert( tag == LBER_INTEGER );
219                 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
220         }
221         tag = ber_skip_tag( ber, &len );        /* Signature Algorithm */
222         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
223         ber_skip_data( ber, len );
224         tag = ber_skip_tag( ber, &len );        /* Issuer DN */
225         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
226         ber_skip_data( ber, len );
227         tag = ber_skip_tag( ber, &len );        /* thisUpdate */
228         /* Time is a CHOICE { UTCTime, GeneralizedTime } */
229         if ( tag != 0x17U && tag != 0x18U ) return LDAP_INVALID_SYNTAX;
230         ber_skip_data( ber, len );
231         /* Optional nextUpdate */
232         tag = ber_skip_tag( ber, &len );
233         if ( tag == 0x17U || tag == 0x18U ) {
234                 ber_skip_data( ber, len );
235                 tag = ber_skip_tag( ber, &len );
236         }
237         /* revokedCertificates - Sequence of Sequence, Optional */
238         if ( tag == LBER_SEQUENCE ) {
239                 ber_len_t seqlen;
240                 if ( ber_peek_tag( ber, &seqlen ) == LBER_SEQUENCE ) {
241                         /* Should NOT be empty */
242                         ber_skip_data( ber, len );
243                         tag = ber_skip_tag( ber, &len );
244                 }
245         }
246         /* Optional Extensions */
247         if ( tag == SLAP_X509_OPT_CL_CRLEXTENSIONS ) { /* ? */
248                 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
249                 tag = ber_skip_tag( ber, &len );
250                 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
251                 ber_skip_data( ber, len );
252                 tag = ber_skip_tag( ber, &len );
253         }
254         /* signatureAlgorithm */
255         if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
256         ber_skip_data( ber, len );
257         tag = ber_skip_tag( ber, &len );
258         /* Signature */
259         if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX; 
260         ber_skip_data( ber, len );
261         tag = ber_skip_tag( ber, &len );
262         /* Must be at end now */
263         if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
264         return LDAP_SUCCESS;
265 }
266
267 int
268 octetStringMatch(
269         int *matchp,
270         slap_mask_t flags,
271         Syntax *syntax,
272         MatchingRule *mr,
273         struct berval *value,
274         void *assertedValue )
275 {
276         struct berval *asserted = (struct berval *) assertedValue;
277         int match = value->bv_len - asserted->bv_len;
278
279         if( match == 0 ) {
280                 match = memcmp( value->bv_val, asserted->bv_val, value->bv_len );
281         }
282
283         *matchp = match;
284         return LDAP_SUCCESS;
285 }
286
287 int
288 octetStringOrderingMatch(
289         int *matchp,
290         slap_mask_t flags,
291         Syntax *syntax,
292         MatchingRule *mr,
293         struct berval *value,
294         void *assertedValue )
295 {
296         struct berval *asserted = (struct berval *) assertedValue;
297         ber_len_t v_len  = value->bv_len;
298         ber_len_t av_len = asserted->bv_len;
299
300         int match = memcmp( value->bv_val, asserted->bv_val,
301                 (v_len < av_len ? v_len : av_len) );
302
303         if( match == 0 ) match = v_len - av_len;
304
305         *matchp = match;
306         return LDAP_SUCCESS;
307 }
308
309 static void
310 hashPreset(
311         HASH_CONTEXT *HASHcontext,
312         struct berval *prefix,
313         char pre,
314         Syntax *syntax,
315         MatchingRule *mr)
316 {
317         HASH_Init(HASHcontext);
318         if(prefix && prefix->bv_len > 0) {
319                 HASH_Update(HASHcontext,
320                         (unsigned char *)prefix->bv_val, prefix->bv_len);
321         }
322         if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
323         HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
324         HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
325         return;
326 }
327
328 static void
329 hashIter(
330         HASH_CONTEXT *HASHcontext,
331         unsigned char *HASHdigest,
332         unsigned char *value,
333         int len)
334 {
335         HASH_CONTEXT ctx = *HASHcontext;
336         HASH_Update( &ctx, value, len );
337         HASH_Final( HASHdigest, &ctx );
338 }
339
340 /* Index generation function */
341 int octetStringIndexer(
342         slap_mask_t use,
343         slap_mask_t flags,
344         Syntax *syntax,
345         MatchingRule *mr,
346         struct berval *prefix,
347         BerVarray values,
348         BerVarray *keysp,
349         void *ctx )
350 {
351         int i;
352         size_t slen, mlen;
353         BerVarray keys;
354         HASH_CONTEXT HASHcontext;
355         unsigned char HASHdigest[HASH_BYTES];
356         struct berval digest;
357         digest.bv_val = (char *)HASHdigest;
358         digest.bv_len = sizeof(HASHdigest);
359
360         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
361                 /* just count them */
362         }
363
364         /* we should have at least one value at this point */
365         assert( i > 0 );
366
367         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
368
369         slen = syntax->ssyn_oidlen;
370         mlen = mr->smr_oidlen;
371
372         hashPreset( &HASHcontext, prefix, 0, syntax, mr);
373         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
374                 hashIter( &HASHcontext, HASHdigest,
375                         (unsigned char *)values[i].bv_val, values[i].bv_len );
376                 ber_dupbv_x( &keys[i], &digest, ctx );
377         }
378
379         BER_BVZERO( &keys[i] );
380
381         *keysp = keys;
382
383         return LDAP_SUCCESS;
384 }
385
386 /* Index generation function */
387 int octetStringFilter(
388         slap_mask_t use,
389         slap_mask_t flags,
390         Syntax *syntax,
391         MatchingRule *mr,
392         struct berval *prefix,
393         void * assertedValue,
394         BerVarray *keysp,
395         void *ctx )
396 {
397         size_t slen, mlen;
398         BerVarray keys;
399         HASH_CONTEXT HASHcontext;
400         unsigned char HASHdigest[HASH_BYTES];
401         struct berval *value = (struct berval *) assertedValue;
402         struct berval digest;
403         digest.bv_val = (char *)HASHdigest;
404         digest.bv_len = sizeof(HASHdigest);
405
406         slen = syntax->ssyn_oidlen;
407         mlen = mr->smr_oidlen;
408
409         keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
410
411         hashPreset( &HASHcontext, prefix, 0, syntax, mr );
412         hashIter( &HASHcontext, HASHdigest,
413                 (unsigned char *)value->bv_val, value->bv_len );
414
415         ber_dupbv_x( keys, &digest, ctx );
416         BER_BVZERO( &keys[1] );
417
418         *keysp = keys;
419
420         return LDAP_SUCCESS;
421 }
422
423 static int
424 octetStringSubstringsMatch(
425         int *matchp,
426         slap_mask_t flags,
427         Syntax *syntax,
428         MatchingRule *mr,
429         struct berval *value,
430         void *assertedValue )
431 {
432         int match = 0;
433         SubstringsAssertion *sub = assertedValue;
434         struct berval left = *value;
435         int i;
436         ber_len_t inlen = 0;
437
438         /* Add up asserted input length */
439         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
440                 inlen += sub->sa_initial.bv_len;
441         }
442         if ( sub->sa_any ) {
443                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
444                         inlen += sub->sa_any[i].bv_len;
445                 }
446         }
447         if ( !BER_BVISNULL( &sub->sa_final ) ) {
448                 inlen += sub->sa_final.bv_len;
449         }
450
451         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
452                 if ( inlen > left.bv_len ) {
453                         match = 1;
454                         goto done;
455                 }
456
457                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
458                         sub->sa_initial.bv_len );
459
460                 if ( match != 0 ) {
461                         goto done;
462                 }
463
464                 left.bv_val += sub->sa_initial.bv_len;
465                 left.bv_len -= sub->sa_initial.bv_len;
466                 inlen -= sub->sa_initial.bv_len;
467         }
468
469         if ( !BER_BVISNULL( &sub->sa_final ) ) {
470                 if ( inlen > left.bv_len ) {
471                         match = 1;
472                         goto done;
473                 }
474
475                 match = memcmp( sub->sa_final.bv_val,
476                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
477                         sub->sa_final.bv_len );
478
479                 if ( match != 0 ) {
480                         goto done;
481                 }
482
483                 left.bv_len -= sub->sa_final.bv_len;
484                 inlen -= sub->sa_final.bv_len;
485         }
486
487         if ( sub->sa_any ) {
488                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
489                         ber_len_t idx;
490                         char *p;
491
492 retry:
493                         if ( inlen > left.bv_len ) {
494                                 /* not enough length */
495                                 match = 1;
496                                 goto done;
497                         }
498
499                         if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
500                                 continue;
501                         }
502
503                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
504
505                         if( p == NULL ) {
506                                 match = 1;
507                                 goto done;
508                         }
509
510                         idx = p - left.bv_val;
511
512                         if ( idx >= left.bv_len ) {
513                                 /* this shouldn't happen */
514                                 return LDAP_OTHER;
515                         }
516
517                         left.bv_val = p;
518                         left.bv_len -= idx;
519
520                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
521                                 /* not enough left */
522                                 match = 1;
523                                 goto done;
524                         }
525
526                         match = memcmp( left.bv_val,
527                                 sub->sa_any[i].bv_val,
528                                 sub->sa_any[i].bv_len );
529
530                         if ( match != 0 ) {
531                                 left.bv_val++;
532                                 left.bv_len--;
533                                 goto retry;
534                         }
535
536                         left.bv_val += sub->sa_any[i].bv_len;
537                         left.bv_len -= sub->sa_any[i].bv_len;
538                         inlen -= sub->sa_any[i].bv_len;
539                 }
540         }
541
542 done:
543         *matchp = match;
544         return LDAP_SUCCESS;
545 }
546
547 /* Substrings Index generation function */
548 static int
549 octetStringSubstringsIndexer(
550         slap_mask_t use,
551         slap_mask_t flags,
552         Syntax *syntax,
553         MatchingRule *mr,
554         struct berval *prefix,
555         BerVarray values,
556         BerVarray *keysp,
557         void *ctx )
558 {
559         ber_len_t i, nkeys;
560         size_t slen, mlen;
561         BerVarray keys;
562
563         HASH_CONTEXT HCany, HCini, HCfin;
564         unsigned char HASHdigest[HASH_BYTES];
565         struct berval digest;
566         digest.bv_val = (char *)HASHdigest;
567         digest.bv_len = sizeof(HASHdigest);
568
569         nkeys = 0;
570
571         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
572                 /* count number of indices to generate */
573                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
574                         if( values[i].bv_len >= index_substr_if_maxlen ) {
575                                 nkeys += index_substr_if_maxlen -
576                                         (index_substr_if_minlen - 1);
577                         } else if( values[i].bv_len >= index_substr_if_minlen ) {
578                                 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
579                         }
580                 }
581
582                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
583                         if( values[i].bv_len >= index_substr_any_len ) {
584                                 nkeys += values[i].bv_len - (index_substr_any_len - 1);
585                         }
586                 }
587
588                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
589                         if( values[i].bv_len >= index_substr_if_maxlen ) {
590                                 nkeys += index_substr_if_maxlen -
591                                         (index_substr_if_minlen - 1);
592                         } else if( values[i].bv_len >= index_substr_if_minlen ) {
593                                 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
594                         }
595                 }
596         }
597
598         if( nkeys == 0 ) {
599                 /* no keys to generate */
600                 *keysp = NULL;
601                 return LDAP_SUCCESS;
602         }
603
604         keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
605
606         slen = syntax->ssyn_oidlen;
607         mlen = mr->smr_oidlen;
608
609         if ( flags & SLAP_INDEX_SUBSTR_ANY )
610                 hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
611         if( flags & SLAP_INDEX_SUBSTR_INITIAL )
612                 hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
613         if( flags & SLAP_INDEX_SUBSTR_FINAL )
614                 hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
615
616         nkeys = 0;
617         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
618                 ber_len_t j,max;
619
620                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
621                         ( values[i].bv_len >= index_substr_any_len ) )
622                 {
623                         max = values[i].bv_len - (index_substr_any_len - 1);
624
625                         for( j=0; j<max; j++ ) {
626                                 hashIter( &HCany, HASHdigest,
627                                         (unsigned char *)&values[i].bv_val[j],
628                                         index_substr_any_len );
629                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
630                         }
631                 }
632
633                 /* skip if too short */ 
634                 if( values[i].bv_len < index_substr_if_minlen ) continue;
635
636                 max = index_substr_if_maxlen < values[i].bv_len
637                         ? index_substr_if_maxlen : values[i].bv_len;
638
639                 for( j=index_substr_if_minlen; j<=max; j++ ) {
640
641                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
642                                 hashIter( &HCini, HASHdigest,
643                                         (unsigned char *)values[i].bv_val, j );
644                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
645                         }
646
647                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
648                                 hashIter( &HCfin, HASHdigest,
649                                         (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
650                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
651                         }
652
653                 }
654         }
655
656         if( nkeys > 0 ) {
657                 BER_BVZERO( &keys[nkeys] );
658                 *keysp = keys;
659         } else {
660                 ch_free( keys );
661                 *keysp = NULL;
662         }
663
664         return LDAP_SUCCESS;
665 }
666
667 static int
668 octetStringSubstringsFilter (
669         slap_mask_t use,
670         slap_mask_t flags,
671         Syntax *syntax,
672         MatchingRule *mr,
673         struct berval *prefix,
674         void * assertedValue,
675         BerVarray *keysp,
676         void *ctx)
677 {
678         SubstringsAssertion *sa;
679         char pre;
680         ber_len_t nkeys = 0;
681         size_t slen, mlen, klen;
682         BerVarray keys;
683         HASH_CONTEXT HASHcontext;
684         unsigned char HASHdigest[HASH_BYTES];
685         struct berval *value;
686         struct berval digest;
687
688         sa = (SubstringsAssertion *) assertedValue;
689
690         if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
691                 !BER_BVISNULL( &sa->sa_initial ) &&
692                 sa->sa_initial.bv_len >= index_substr_if_minlen )
693         {
694                 nkeys++;
695                 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
696                         ( flags & SLAP_INDEX_SUBSTR_ANY ))
697                 {
698                         nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
699                 }
700         }
701
702         if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
703                 ber_len_t i;
704                 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
705                         if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
706                                 /* don't bother accounting with stepping */
707                                 nkeys += sa->sa_any[i].bv_len -
708                                         ( index_substr_any_len - 1 );
709                         }
710                 }
711         }
712
713         if( flags & SLAP_INDEX_SUBSTR_FINAL &&
714                 !BER_BVISNULL( &sa->sa_final ) &&
715                 sa->sa_final.bv_len >= index_substr_if_minlen )
716         {
717                 nkeys++;
718                 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
719                         ( flags & SLAP_INDEX_SUBSTR_ANY ))
720                 {
721                         nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
722                 }
723         }
724
725         if( nkeys == 0 ) {
726                 *keysp = NULL;
727                 return LDAP_SUCCESS;
728         }
729
730         digest.bv_val = (char *)HASHdigest;
731         digest.bv_len = sizeof(HASHdigest);
732
733         slen = syntax->ssyn_oidlen;
734         mlen = mr->smr_oidlen;
735
736         keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
737         nkeys = 0;
738
739         if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
740                 !BER_BVISNULL( &sa->sa_initial ) &&
741                 sa->sa_initial.bv_len >= index_substr_if_minlen )
742         {
743                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
744                 value = &sa->sa_initial;
745
746                 klen = index_substr_if_maxlen < value->bv_len
747                         ? index_substr_if_maxlen : value->bv_len;
748
749                 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
750                 hashIter( &HASHcontext, HASHdigest,
751                         (unsigned char *)value->bv_val, klen );
752                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
753
754                 /* If initial is too long and we have subany indexed, use it
755                  * to match the excess...
756                  */
757                 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
758                 {
759                         ber_len_t j;
760                         pre = SLAP_INDEX_SUBSTR_PREFIX;
761                         hashPreset( &HASHcontext, prefix, pre, syntax, mr);
762                         for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
763                         {
764                                 hashIter( &HASHcontext, HASHdigest,
765                                         (unsigned char *)&value->bv_val[j], index_substr_any_len );
766                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
767                         }
768                 }
769         }
770
771         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
772                 ber_len_t i, j;
773                 pre = SLAP_INDEX_SUBSTR_PREFIX;
774                 klen = index_substr_any_len;
775
776                 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
777                         if( sa->sa_any[i].bv_len < index_substr_any_len ) {
778                                 continue;
779                         }
780
781                         value = &sa->sa_any[i];
782
783                         hashPreset( &HASHcontext, prefix, pre, syntax, mr);
784                         for(j=0;
785                                 j <= value->bv_len - index_substr_any_len;
786                                 j += index_substr_any_step )
787                         {
788                                 hashIter( &HASHcontext, HASHdigest,
789                                         (unsigned char *)&value->bv_val[j], klen ); 
790                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
791                         }
792                 }
793         }
794
795         if( flags & SLAP_INDEX_SUBSTR_FINAL &&
796                 !BER_BVISNULL( &sa->sa_final ) &&
797                 sa->sa_final.bv_len >= index_substr_if_minlen )
798         {
799                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
800                 value = &sa->sa_final;
801
802                 klen = index_substr_if_maxlen < value->bv_len
803                         ? index_substr_if_maxlen : value->bv_len;
804
805                 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
806                 hashIter( &HASHcontext, HASHdigest,
807                         (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
808                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
809
810                 /* If final is too long and we have subany indexed, use it
811                  * to match the excess...
812                  */
813                 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
814                 {
815                         ber_len_t j;
816                         pre = SLAP_INDEX_SUBSTR_PREFIX;
817                         hashPreset( &HASHcontext, prefix, pre, syntax, mr);
818                         for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
819                         {
820                                 hashIter( &HASHcontext, HASHdigest,
821                                         (unsigned char *)&value->bv_val[j], index_substr_any_len );
822                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
823                         }
824                 }
825         }
826
827         if( nkeys > 0 ) {
828                 BER_BVZERO( &keys[nkeys] );
829                 *keysp = keys;
830         } else {
831                 ch_free( keys );
832                 *keysp = NULL;
833         }
834
835         return LDAP_SUCCESS;
836 }
837
838 static int
839 bitStringValidate(
840         Syntax *syntax,
841         struct berval *in )
842 {
843         ber_len_t i;
844
845         /* very unforgiving validation, requires no normalization
846          * before simplistic matching
847          */
848         if( in->bv_len < 3 ) {
849                 return LDAP_INVALID_SYNTAX;
850         }
851
852         /* RFC 4517 Section 3.3.2 Bit String:
853      *  BitString    = SQUOTE *binary-digit SQUOTE "B"
854      *  binary-digit = "0" / "1"
855          *
856          * where SQUOTE [RFC4512] is
857          *      SQUOTE  = %x27 ; single quote ("'")
858          *
859          * Example: '0101111101'B
860          */
861         
862         if( in->bv_val[0] != '\'' ||
863                 in->bv_val[in->bv_len - 2] != '\'' ||
864                 in->bv_val[in->bv_len - 1] != 'B' )
865         {
866                 return LDAP_INVALID_SYNTAX;
867         }
868
869         for( i = in->bv_len - 3; i > 0; i-- ) {
870                 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
871                         return LDAP_INVALID_SYNTAX;
872                 }
873         }
874
875         return LDAP_SUCCESS;
876 }
877
878 /*
879  * Syntaxes from RFC 4517
880  *
881
882 3.3.2.  Bit String
883
884    A value of the Bit String syntax is a sequence of binary digits.  The
885    LDAP-specific encoding of a value of this syntax is defined by the
886    following ABNF:
887
888       BitString    = SQUOTE *binary-digit SQUOTE "B"
889
890       binary-digit = "0" / "1"
891
892    The <SQUOTE> rule is defined in [MODELS].
893
894       Example:
895          '0101111101'B
896
897    The LDAP definition for the Bit String syntax is:
898
899       ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
900
901    This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
902
903    ...
904
905 3.3.21.  Name and Optional UID
906
907    A value of the Name and Optional UID syntax is the distinguished name
908    [MODELS] of an entity optionally accompanied by a unique identifier
909    that serves to differentiate the entity from others with an identical
910    distinguished name.
911
912    The LDAP-specific encoding of a value of this syntax is defined by
913    the following ABNF:
914
915        NameAndOptionalUID = distinguishedName [ SHARP BitString ]
916
917    The <BitString> rule is defined in Section 3.3.2.  The
918    <distinguishedName> rule is defined in [LDAPDN].  The <SHARP> rule is
919    defined in [MODELS].
920
921    Note that although the '#' character may occur in the string
922    representation of a distinguished name, no additional escaping of
923    this character is performed when a <distinguishedName> is encoded in
924    a <NameAndOptionalUID>.
925
926       Example:
927          1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
928
929    The LDAP definition for the Name and Optional UID syntax is:
930
931       ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
932
933    This syntax corresponds to the NameAndOptionalUID ASN.1 type from
934    [X.520].
935
936  *
937  * RFC 4512 says:
938  *
939
940 1.4. Common ABNF Productions
941
942   ...
943       SHARP   = %x23 ; octothorpe (or sharp sign) ("#")
944   ...
945       SQUOTE  = %x27 ; single quote ("'")
946   ...
947       
948  *
949  * Note: normalization strips any leading "0"s, unless the
950  * bit string is exactly "'0'B", so the normalized example,
951  * in slapd, would result in
952  * 
953  * 1.3.6.1.4.1.1466.0=#04024869,o=test,c=gb#'101'B
954  * 
955  * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
956  * be escaped except when at the beginning of a value, the
957  * definition of Name and Optional UID appears to be flawed,
958  * because there is no clear means to determine whether the
959  * UID part is present or not.
960  *
961  * Example:
962  *
963  *      cn=Someone,dc=example,dc=com#'1'B
964  *
965  * could be either a NameAndOptionalUID with trailing UID, i.e.
966  *
967  *      DN = "cn=Someone,dc=example,dc=com"
968  *      UID = "'1'B"
969  * 
970  * or a NameAndOptionalUID with no trailing UID, and the AVA
971  * in the last RDN made of
972  *
973  *      attributeType = dc 
974  *      attributeValue = com#'1'B
975  *
976  * in fact "com#'1'B" is a valid IA5 string.
977  *
978  * As a consequence, current slapd code assumes that the
979  * presence of portions of a BitString at the end of the string 
980  * representation of a NameAndOptionalUID means a BitString
981  * is expected, and cause an error otherwise.  This is quite
982  * arbitrary, and might change in the future.
983  */
984
985
986 static int
987 nameUIDValidate(
988         Syntax *syntax,
989         struct berval *in )
990 {
991         int rc;
992         struct berval dn, uid;
993
994         if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
995
996         ber_dupbv( &dn, in );
997         if( !dn.bv_val ) return LDAP_OTHER;
998
999         /* if there's a "#", try bitStringValidate()... */
1000         uid.bv_val = strrchr( dn.bv_val, '#' );
1001         if ( !BER_BVISNULL( &uid ) ) {
1002                 uid.bv_val++;
1003                 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
1004
1005                 rc = bitStringValidate( NULL, &uid );
1006                 if ( rc == LDAP_SUCCESS ) {
1007                         /* in case of success, trim the UID,
1008                          * otherwise treat it as part of the DN */
1009                         dn.bv_len -= uid.bv_len + 1;
1010                         uid.bv_val[-1] = '\0';
1011                 }
1012         }
1013
1014         rc = dnValidate( NULL, &dn );
1015
1016         ber_memfree( dn.bv_val );
1017         return rc;
1018 }
1019
1020 int
1021 nameUIDPretty(
1022         Syntax *syntax,
1023         struct berval *val,
1024         struct berval *out,
1025         void *ctx )
1026 {
1027         assert( val != NULL );
1028         assert( out != NULL );
1029
1030
1031         Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
1032
1033         if( BER_BVISEMPTY( val ) ) {
1034                 ber_dupbv_x( out, val, ctx );
1035
1036         } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
1037                 return LDAP_INVALID_SYNTAX;
1038
1039         } else {
1040                 int             rc;
1041                 struct berval   dnval = *val;
1042                 struct berval   uidval = BER_BVNULL;
1043
1044                 uidval.bv_val = strrchr( val->bv_val, '#' );
1045                 if ( !BER_BVISNULL( &uidval ) ) {
1046                         uidval.bv_val++;
1047                         uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
1048
1049                         rc = bitStringValidate( NULL, &uidval );
1050
1051                         if ( rc == LDAP_SUCCESS ) {
1052                                 ber_dupbv_x( &dnval, val, ctx );
1053                                 dnval.bv_len -= uidval.bv_len + 1;
1054                                 dnval.bv_val[dnval.bv_len] = '\0';
1055
1056                         } else {
1057                                 BER_BVZERO( &uidval );
1058                         }
1059                 }
1060
1061                 rc = dnPretty( syntax, &dnval, out, ctx );
1062                 if ( dnval.bv_val != val->bv_val ) {
1063                         slap_sl_free( dnval.bv_val, ctx );
1064                 }
1065                 if( rc != LDAP_SUCCESS ) {
1066                         return rc;
1067                 }
1068
1069                 if( !BER_BVISNULL( &uidval ) ) {
1070                         int     i, c, got1;
1071                         char    *tmp;
1072
1073                         tmp = slap_sl_realloc( out->bv_val, out->bv_len 
1074                                 + STRLENOF( "#" ) + uidval.bv_len + 1,
1075                                 ctx );
1076                         if( tmp == NULL ) {
1077                                 ber_memfree_x( out->bv_val, ctx );
1078                                 return LDAP_OTHER;
1079                         }
1080                         out->bv_val = tmp;
1081                         out->bv_val[out->bv_len++] = '#';
1082                         out->bv_val[out->bv_len++] = '\'';
1083
1084                         got1 = uidval.bv_len < sizeof("'0'B"); 
1085                         for( i = 1; i < uidval.bv_len - 2; i++ ) {
1086                                 c = uidval.bv_val[i];
1087                                 switch(c) {
1088                                         case '0':
1089                                                 if( got1 ) out->bv_val[out->bv_len++] = c;
1090                                                 break;
1091                                         case '1':
1092                                                 got1 = 1;
1093                                                 out->bv_val[out->bv_len++] = c;
1094                                                 break;
1095                                 }
1096                         }
1097
1098                         out->bv_val[out->bv_len++] = '\'';
1099                         out->bv_val[out->bv_len++] = 'B';
1100                         out->bv_val[out->bv_len] = '\0';
1101                 }
1102         }
1103
1104         Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1105
1106         return LDAP_SUCCESS;
1107 }
1108
1109 static int
1110 uniqueMemberNormalize(
1111         slap_mask_t usage,
1112         Syntax *syntax,
1113         MatchingRule *mr,
1114         struct berval *val,
1115         struct berval *normalized,
1116         void *ctx )
1117 {
1118         struct berval out;
1119         int rc;
1120
1121         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1122
1123         ber_dupbv_x( &out, val, ctx );
1124         if ( BER_BVISEMPTY( &out ) ) {
1125                 *normalized = out;
1126
1127         } else {
1128                 struct berval uid = BER_BVNULL;
1129
1130                 uid.bv_val = strrchr( out.bv_val, '#' );
1131                 if ( !BER_BVISNULL( &uid ) ) {
1132                         uid.bv_val++;
1133                         uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1134
1135                         rc = bitStringValidate( NULL, &uid );
1136                         if ( rc == LDAP_SUCCESS ) {
1137                                 uid.bv_val[-1] = '\0';
1138                                 out.bv_len -= uid.bv_len + 1;
1139                         } else {
1140                                 BER_BVZERO( &uid );
1141                         }
1142                 }
1143
1144                 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1145
1146                 if( rc != LDAP_SUCCESS ) {
1147                         slap_sl_free( out.bv_val, ctx );
1148                         return LDAP_INVALID_SYNTAX;
1149                 }
1150
1151                 if( !BER_BVISNULL( &uid ) ) {
1152                         char    *tmp;
1153
1154                         tmp = ch_realloc( normalized->bv_val,
1155                                 normalized->bv_len + uid.bv_len
1156                                 + STRLENOF("#") + 1 );
1157                         if ( tmp == NULL ) {
1158                                 ber_memfree_x( normalized->bv_val, ctx );
1159                                 return LDAP_OTHER;
1160                         }
1161
1162                         normalized->bv_val = tmp;
1163
1164                         /* insert the separator */
1165                         normalized->bv_val[normalized->bv_len++] = '#';
1166
1167                         /* append the UID */
1168                         AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1169                                 uid.bv_val, uid.bv_len );
1170                         normalized->bv_len += uid.bv_len;
1171
1172                         /* terminate */
1173                         normalized->bv_val[normalized->bv_len] = '\0';
1174                 }
1175
1176                 slap_sl_free( out.bv_val, ctx );
1177         }
1178
1179         return LDAP_SUCCESS;
1180 }
1181
1182 static int
1183 uniqueMemberMatch(
1184         int *matchp,
1185         slap_mask_t flags,
1186         Syntax *syntax,
1187         MatchingRule *mr,
1188         struct berval *value,
1189         void *assertedValue )
1190 {
1191         int match;
1192         struct berval *asserted = (struct berval *) assertedValue;
1193         struct berval assertedDN = *asserted;
1194         struct berval assertedUID = BER_BVNULL;
1195         struct berval valueDN = *value;
1196         struct berval valueUID = BER_BVNULL;
1197         int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1198
1199         if ( !BER_BVISEMPTY( asserted ) ) {
1200                 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1201                 if ( !BER_BVISNULL( &assertedUID ) ) {
1202                         assertedUID.bv_val++;
1203                         assertedUID.bv_len = assertedDN.bv_len
1204                                 - ( assertedUID.bv_val - assertedDN.bv_val );
1205
1206                         if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1207                                 assertedDN.bv_len -= assertedUID.bv_len + 1;
1208
1209                         } else {
1210                                 BER_BVZERO( &assertedUID );
1211                         }
1212                 }
1213         }
1214
1215         if ( !BER_BVISEMPTY( value ) ) {
1216
1217                 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1218                 if ( !BER_BVISNULL( &valueUID ) ) {
1219                         valueUID.bv_val++;
1220                         valueUID.bv_len = valueDN.bv_len
1221                                 - ( valueUID.bv_val - valueDN.bv_val );
1222
1223                         if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1224                                 valueDN.bv_len -= valueUID.bv_len + 1;
1225
1226                         } else {
1227                                 BER_BVZERO( &valueUID );
1228                         }
1229                 }
1230         }
1231
1232         if( valueUID.bv_len && assertedUID.bv_len ) {
1233                 match = valueUID.bv_len - assertedUID.bv_len;
1234                 if ( match ) {
1235                         *matchp = match;
1236                         return LDAP_SUCCESS;
1237                 }
1238
1239                 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1240                 if( match ) {
1241                         *matchp = match;
1242                         return LDAP_SUCCESS;
1243                 }
1244
1245         } else if ( !approx && valueUID.bv_len ) {
1246                 match = -1;
1247                 *matchp = match;
1248                 return LDAP_SUCCESS;
1249
1250         } else if ( !approx && assertedUID.bv_len ) {
1251                 match = 1;
1252                 *matchp = match;
1253                 return LDAP_SUCCESS;
1254         }
1255
1256         return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1257 }
1258
1259 static int 
1260 uniqueMemberIndexer(
1261         slap_mask_t use,
1262         slap_mask_t flags,
1263         Syntax *syntax,
1264         MatchingRule *mr,
1265         struct berval *prefix,
1266         BerVarray values,
1267         BerVarray *keysp,
1268         void *ctx )
1269 {
1270         BerVarray dnvalues;
1271         int rc;
1272         int i;
1273         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1274                 /* just count them */                 
1275         }
1276         assert( i > 0 );
1277
1278         dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1279
1280         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1281                 struct berval assertedDN = values[i];
1282                 struct berval assertedUID = BER_BVNULL;
1283
1284                 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1285                         assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1286                         if ( !BER_BVISNULL( &assertedUID ) ) {
1287                                 assertedUID.bv_val++;
1288                                 assertedUID.bv_len = assertedDN.bv_len
1289                                         - ( assertedUID.bv_val - assertedDN.bv_val );
1290         
1291                                 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1292                                         assertedDN.bv_len -= assertedUID.bv_len + 1;
1293
1294                                 } else {
1295                                         BER_BVZERO( &assertedUID );
1296                                 }
1297                         }
1298                 }
1299
1300                 dnvalues[i] = assertedDN;
1301         }
1302         BER_BVZERO( &dnvalues[i] );
1303
1304         rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1305                 dnvalues, keysp, ctx );
1306
1307         slap_sl_free( dnvalues, ctx );
1308         return rc;
1309 }
1310
1311 static int 
1312 uniqueMemberFilter(
1313         slap_mask_t use,
1314         slap_mask_t flags,
1315         Syntax *syntax,
1316         MatchingRule *mr,
1317         struct berval *prefix,
1318         void * assertedValue,
1319         BerVarray *keysp,
1320         void *ctx )
1321 {
1322         struct berval *asserted = (struct berval *) assertedValue;
1323         struct berval assertedDN = *asserted;
1324         struct berval assertedUID = BER_BVNULL;
1325
1326         if ( !BER_BVISEMPTY( asserted ) ) {
1327                 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1328                 if ( !BER_BVISNULL( &assertedUID ) ) {
1329                         assertedUID.bv_val++;
1330                         assertedUID.bv_len = assertedDN.bv_len
1331                                 - ( assertedUID.bv_val - assertedDN.bv_val );
1332
1333                         if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1334                                 assertedDN.bv_len -= assertedUID.bv_len + 1;
1335
1336                         } else {
1337                                 BER_BVZERO( &assertedUID );
1338                         }
1339                 }
1340         }
1341
1342         return octetStringFilter( use, flags, syntax, mr, prefix,
1343                 &assertedDN, keysp, ctx );
1344 }
1345
1346
1347 /*
1348  * Handling boolean syntax and matching is quite rigid.
1349  * A more flexible approach would be to allow a variety
1350  * of strings to be normalized and prettied into TRUE
1351  * and FALSE.
1352  */
1353 static int
1354 booleanValidate(
1355         Syntax *syntax,
1356         struct berval *in )
1357 {
1358         /* very unforgiving validation, requires no normalization
1359          * before simplistic matching
1360          */
1361
1362         if( in->bv_len == 4 ) {
1363                 if( bvmatch( in, &slap_true_bv ) ) {
1364                         return LDAP_SUCCESS;
1365                 }
1366         } else if( in->bv_len == 5 ) {
1367                 if( bvmatch( in, &slap_false_bv ) ) {
1368                         return LDAP_SUCCESS;
1369                 }
1370         }
1371
1372         return LDAP_INVALID_SYNTAX;
1373 }
1374
1375 static int
1376 booleanMatch(
1377         int *matchp,
1378         slap_mask_t flags,
1379         Syntax *syntax,
1380         MatchingRule *mr,
1381         struct berval *value,
1382         void *assertedValue )
1383 {
1384         /* simplistic matching allowed by rigid validation */
1385         struct berval *asserted = (struct berval *) assertedValue;
1386         *matchp = value->bv_len != asserted->bv_len;
1387         return LDAP_SUCCESS;
1388 }
1389
1390 /*-------------------------------------------------------------------
1391 LDAP/X.500 string syntax / matching rules have a few oddities.  This
1392 comment attempts to detail how slapd(8) treats them.
1393
1394 Summary:
1395   StringSyntax          X.500   LDAP    Matching/Comments
1396   DirectoryString       CHOICE  UTF8    i/e + ignore insignificant spaces
1397   PrintableString       subset  subset  i/e + ignore insignificant spaces
1398   PrintableString       subset  subset  i/e + ignore insignificant spaces
1399   NumericString         subset  subset  ignore all spaces
1400   IA5String                     ASCII   ASCII   i/e + ignore insignificant spaces
1401   TeletexString         T.61    T.61    i/e + ignore insignificant spaces
1402
1403   TelephoneNumber       subset  subset  i + ignore all spaces and "-"
1404
1405   See RFC 4518 for details.
1406
1407
1408 Directory String -
1409   In X.500(93), a directory string can be either a PrintableString,
1410   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1411   In later versions, more CHOICEs were added.  In all cases the string
1412   must be non-empty.
1413
1414   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1415   A directory string cannot be zero length.
1416
1417   For matching, there are both case ignore and exact rules.  Both
1418   also require that "insignificant" spaces be ignored.
1419         spaces before the first non-space are ignored;
1420         spaces after the last non-space are ignored;
1421         spaces after a space are ignored.
1422   Note: by these rules (and as clarified in X.520), a string of only
1423   spaces is to be treated as if held one space, not empty (which
1424   would be a syntax error).
1425
1426 NumericString
1427   In ASN.1, numeric string is just a string of digits and spaces
1428   and could be empty.  However, in X.500, all attribute values of
1429   numeric string carry a non-empty constraint.  For example:
1430
1431         internationalISDNNumber ATTRIBUTE ::= {
1432                 WITH SYNTAX InternationalISDNNumber
1433                 EQUALITY MATCHING RULE numericStringMatch
1434                 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1435                 ID id-at-internationalISDNNumber }
1436         InternationalISDNNumber ::=
1437             NumericString (SIZE(1..ub-international-isdn-number))
1438
1439   Unforunately, some assertion values are don't carry the same
1440   constraint (but its unclear how such an assertion could ever
1441   be true). In LDAP, there is one syntax (numericString) not two
1442   (numericString with constraint, numericString without constraint).
1443   This should be treated as numericString with non-empty constraint.
1444   Note that while someone may have no ISDN number, there are no ISDN
1445   numbers which are zero length.
1446
1447   In matching, spaces are ignored.
1448
1449 PrintableString
1450   In ASN.1, Printable string is just a string of printable characters
1451   and can be empty.  In X.500, semantics much like NumericString (see
1452   serialNumber for a like example) excepting uses insignificant space
1453   handling instead of ignore all spaces.  They must be non-empty.
1454
1455 IA5String
1456   Basically same as PrintableString.  There are no examples in X.500,
1457   but same logic applies.  Empty strings are allowed.
1458
1459 -------------------------------------------------------------------*/
1460
1461 static int
1462 UTF8StringValidate(
1463         Syntax *syntax,
1464         struct berval *in )
1465 {
1466         ber_len_t count;
1467         int len;
1468         unsigned char *u = (unsigned char *)in->bv_val;
1469
1470         if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1471                 /* directory strings cannot be empty */
1472                 return LDAP_INVALID_SYNTAX;
1473         }
1474
1475         for( count = in->bv_len; count > 0; count -= len, u += len ) {
1476                 /* get the length indicated by the first byte */
1477                 len = LDAP_UTF8_CHARLEN2( u, len );
1478
1479                 /* very basic checks */
1480                 switch( len ) {
1481                         case 6:
1482                                 if( (u[5] & 0xC0) != 0x80 ) {
1483                                         return LDAP_INVALID_SYNTAX;
1484                                 }
1485                         case 5:
1486                                 if( (u[4] & 0xC0) != 0x80 ) {
1487                                         return LDAP_INVALID_SYNTAX;
1488                                 }
1489                         case 4:
1490                                 if( (u[3] & 0xC0) != 0x80 ) {
1491                                         return LDAP_INVALID_SYNTAX;
1492                                 }
1493                         case 3:
1494                                 if( (u[2] & 0xC0 )!= 0x80 ) {
1495                                         return LDAP_INVALID_SYNTAX;
1496                                 }
1497                         case 2:
1498                                 if( (u[1] & 0xC0) != 0x80 ) {
1499                                         return LDAP_INVALID_SYNTAX;
1500                                 }
1501                         case 1:
1502                                 /* CHARLEN already validated it */
1503                                 break;
1504                         default:
1505                                 return LDAP_INVALID_SYNTAX;
1506                 }
1507
1508                 /* make sure len corresponds with the offset
1509                         to the next character */
1510                 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1511         }
1512
1513         if( count != 0 ) {
1514                 return LDAP_INVALID_SYNTAX;
1515         }
1516
1517         return LDAP_SUCCESS;
1518 }
1519
1520 static int
1521 UTF8StringNormalize(
1522         slap_mask_t use,
1523         Syntax *syntax,
1524         MatchingRule *mr,
1525         struct berval *val,
1526         struct berval *normalized,
1527         void *ctx )
1528 {
1529         struct berval tmp, nvalue;
1530         int flags;
1531         int i, wasspace;
1532
1533         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
1534
1535         if( BER_BVISNULL( val ) ) {
1536                 /* assume we're dealing with a syntax (e.g., UTF8String)
1537                  * which allows empty strings
1538                  */
1539                 BER_BVZERO( normalized );
1540                 return LDAP_SUCCESS;
1541         }
1542
1543         flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1544                 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1545         flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1546                 ? LDAP_UTF8_APPROX : 0;
1547
1548         val = UTF8bvnormalize( val, &tmp, flags, ctx );
1549         if( val == NULL ) {
1550                 return LDAP_OTHER;
1551         }
1552         
1553         /* collapse spaces (in place) */
1554         nvalue.bv_len = 0;
1555         nvalue.bv_val = tmp.bv_val;
1556
1557         /* trim leading spaces? */
1558         wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1559                 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1560
1561         for( i = 0; i < tmp.bv_len; i++) {
1562                 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1563                         if( wasspace++ == 0 ) {
1564                                 /* trim repeated spaces */
1565                                 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1566                         }
1567                 } else {
1568                         wasspace = 0;
1569                         nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1570                 }
1571         }
1572
1573         if( !BER_BVISEMPTY( &nvalue ) ) {
1574                 /* trim trailing space? */
1575                 if( wasspace && (
1576                         (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1577                         ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1578                 {
1579                         --nvalue.bv_len;
1580                 }
1581                 nvalue.bv_val[nvalue.bv_len] = '\0';
1582
1583         } else {
1584                 /* string of all spaces is treated as one space */
1585                 nvalue.bv_val[0] = ' ';
1586                 nvalue.bv_val[1] = '\0';
1587                 nvalue.bv_len = 1;
1588         }
1589
1590         *normalized = nvalue;
1591         return LDAP_SUCCESS;
1592 }
1593
1594 static int
1595 directoryStringSubstringsMatch(
1596         int *matchp,
1597         slap_mask_t flags,
1598         Syntax *syntax,
1599         MatchingRule *mr,
1600         struct berval *value,
1601         void *assertedValue )
1602 {
1603         int match = 0;
1604         SubstringsAssertion *sub = assertedValue;
1605         struct berval left = *value;
1606         int i;
1607         int priorspace=0;
1608
1609         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1610                 if ( sub->sa_initial.bv_len > left.bv_len ) {
1611                         /* not enough left */
1612                         match = 1;
1613                         goto done;
1614                 }
1615
1616                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1617                         sub->sa_initial.bv_len );
1618
1619                 if ( match != 0 ) {
1620                         goto done;
1621                 }
1622
1623                 left.bv_val += sub->sa_initial.bv_len;
1624                 left.bv_len -= sub->sa_initial.bv_len;
1625
1626                 priorspace = ASCII_SPACE(
1627                         sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1628         }
1629
1630         if ( sub->sa_any ) {
1631                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1632                         ber_len_t idx;
1633                         char *p;
1634
1635                         if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] ) 
1636                                 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1637                         { 
1638                                 /* allow next space to match */
1639                                 left.bv_val--;
1640                                 left.bv_len++;
1641                         }
1642                         priorspace=0;
1643
1644 retry:
1645                         if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1646                                 continue;
1647                         }
1648
1649                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1650                                 /* not enough left */
1651                                 match = 1;
1652                                 goto done;
1653                         }
1654
1655                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1656
1657                         if( p == NULL ) {
1658                                 match = 1;
1659                                 goto done;
1660                         }
1661
1662                         idx = p - left.bv_val;
1663
1664                         if ( idx >= left.bv_len ) {
1665                                 /* this shouldn't happen */
1666                                 return LDAP_OTHER;
1667                         }
1668
1669                         left.bv_val = p;
1670                         left.bv_len -= idx;
1671
1672                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1673                                 /* not enough left */
1674                                 match = 1;
1675                                 goto done;
1676                         }
1677
1678                         match = memcmp( left.bv_val,
1679                                 sub->sa_any[i].bv_val,
1680                                 sub->sa_any[i].bv_len );
1681
1682                         if ( match != 0 ) {
1683                                 left.bv_val++;
1684                                 left.bv_len--;
1685                                 goto retry;
1686                         }
1687
1688                         left.bv_val += sub->sa_any[i].bv_len;
1689                         left.bv_len -= sub->sa_any[i].bv_len;
1690
1691                         priorspace = ASCII_SPACE(
1692                                 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1693                 }
1694         }
1695
1696         if ( !BER_BVISNULL( &sub->sa_final ) ) {
1697                 if( priorspace && !BER_BVISEMPTY( &sub->sa_final ) 
1698                         && ASCII_SPACE( sub->sa_final.bv_val[0] ))
1699                 { 
1700                         /* allow next space to match */
1701                         left.bv_val--;
1702                         left.bv_len++;
1703                 }
1704
1705                 if ( sub->sa_final.bv_len > left.bv_len ) {
1706                         /* not enough left */
1707                         match = 1;
1708                         goto done;
1709                 }
1710
1711                 match = memcmp( sub->sa_final.bv_val,
1712                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1713                         sub->sa_final.bv_len );
1714
1715                 if ( match != 0 ) {
1716                         goto done;
1717                 }
1718         }
1719
1720 done:
1721         *matchp = match;
1722         return LDAP_SUCCESS;
1723 }
1724
1725 #if defined(SLAPD_APPROX_INITIALS)
1726 #       define SLAPD_APPROX_DELIMITER "._ "
1727 #       define SLAPD_APPROX_WORDLEN 2
1728 #else
1729 #       define SLAPD_APPROX_DELIMITER " "
1730 #       define SLAPD_APPROX_WORDLEN 1
1731 #endif
1732
1733 static int
1734 approxMatch(
1735         int *matchp,
1736         slap_mask_t flags,
1737         Syntax *syntax,
1738         MatchingRule *mr,
1739         struct berval *value,
1740         void *assertedValue )
1741 {
1742         struct berval *nval, *assertv;
1743         char *val, **values, **words, *c;
1744         int i, count, len, nextchunk=0, nextavail=0;
1745
1746         /* Yes, this is necessary */
1747         nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
1748         if( nval == NULL ) {
1749                 *matchp = 1;
1750                 return LDAP_SUCCESS;
1751         }
1752
1753         /* Yes, this is necessary */
1754         assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1755                 NULL, LDAP_UTF8_APPROX, NULL );
1756         if( assertv == NULL ) {
1757                 ber_bvfree( nval );
1758                 *matchp = 1;
1759                 return LDAP_SUCCESS;
1760         }
1761
1762         /* Isolate how many words there are */
1763         for ( c = nval->bv_val, count = 1; *c; c++ ) {
1764                 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1765                 if ( c == NULL ) break;
1766                 *c = '\0';
1767                 count++;
1768         }
1769
1770         /* Get a phonetic copy of each word */
1771         words = (char **)ch_malloc( count * sizeof(char *) );
1772         values = (char **)ch_malloc( count * sizeof(char *) );
1773         for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
1774                 words[i] = c;
1775                 values[i] = phonetic(c);
1776         }
1777
1778         /* Work through the asserted value's words, to see if at least some
1779            of the words are there, in the same order. */
1780         len = 0;
1781         while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1782                 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1783                 if( len == 0 ) {
1784                         nextchunk++;
1785                         continue;
1786                 }
1787 #if defined(SLAPD_APPROX_INITIALS)
1788                 else if( len == 1 ) {
1789                         /* Single letter words need to at least match one word's initial */
1790                         for( i=nextavail; i<count; i++ )
1791                                 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1792                                         nextavail=i+1;
1793                                         break;
1794                                 }
1795                 }
1796 #endif
1797                 else {
1798                         /* Isolate the next word in the asserted value and phonetic it */
1799                         assertv->bv_val[nextchunk+len] = '\0';
1800                         val = phonetic( assertv->bv_val + nextchunk );
1801
1802                         /* See if this phonetic chunk is in the remaining words of *value */
1803                         for( i=nextavail; i<count; i++ ){
1804                                 if( !strcmp( val, values[i] ) ){
1805                                         nextavail = i+1;
1806                                         break;
1807                                 }
1808                         }
1809                         ch_free( val );
1810                 }
1811
1812                 /* This chunk in the asserted value was NOT within the *value. */
1813                 if( i >= count ) {
1814                         nextavail=-1;
1815                         break;
1816                 }
1817
1818                 /* Go on to the next word in the asserted value */
1819                 nextchunk += len+1;
1820         }
1821
1822         /* If some of the words were seen, call it a match */
1823         if( nextavail > 0 ) {
1824                 *matchp = 0;
1825         }
1826         else {
1827                 *matchp = 1;
1828         }
1829
1830         /* Cleanup allocs */
1831         ber_bvfree( assertv );
1832         for( i=0; i<count; i++ ) {
1833                 ch_free( values[i] );
1834         }
1835         ch_free( values );
1836         ch_free( words );
1837         ber_bvfree( nval );
1838
1839         return LDAP_SUCCESS;
1840 }
1841
1842 static int 
1843 approxIndexer(
1844         slap_mask_t use,
1845         slap_mask_t flags,
1846         Syntax *syntax,
1847         MatchingRule *mr,
1848         struct berval *prefix,
1849         BerVarray values,
1850         BerVarray *keysp,
1851         void *ctx )
1852 {
1853         char *c;
1854         int i,j, len, wordcount, keycount=0;
1855         struct berval *newkeys;
1856         BerVarray keys=NULL;
1857
1858         for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
1859                 struct berval val = BER_BVNULL;
1860                 /* Yes, this is necessary */
1861                 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
1862                 assert( !BER_BVISNULL( &val ) );
1863
1864                 /* Isolate how many words there are. There will be a key for each */
1865                 for( wordcount = 0, c = val.bv_val; *c; c++) {
1866                         len = strcspn(c, SLAPD_APPROX_DELIMITER);
1867                         if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1868                         c+= len;
1869                         if (*c == '\0') break;
1870                         *c = '\0';
1871                 }
1872
1873                 /* Allocate/increase storage to account for new keys */
1874                 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
1875                         * sizeof(struct berval) );
1876                 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1877                 if( keys ) ch_free( keys );
1878                 keys = newkeys;
1879
1880                 /* Get a phonetic copy of each word */
1881                 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1882                         len = strlen( c );
1883                         if( len < SLAPD_APPROX_WORDLEN ) continue;
1884                         ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1885                         keycount++;
1886                         i++;
1887                 }
1888
1889                 ber_memfree( val.bv_val );
1890         }
1891         BER_BVZERO( &keys[keycount] );
1892         *keysp = keys;
1893
1894         return LDAP_SUCCESS;
1895 }
1896
1897 static int 
1898 approxFilter(
1899         slap_mask_t use,
1900         slap_mask_t flags,
1901         Syntax *syntax,
1902         MatchingRule *mr,
1903         struct berval *prefix,
1904         void * assertedValue,
1905         BerVarray *keysp,
1906         void *ctx )
1907 {
1908         char *c;
1909         int i, count, len;
1910         struct berval *val;
1911         BerVarray keys;
1912
1913         /* Yes, this is necessary */
1914         val = UTF8bvnormalize( ((struct berval *)assertedValue),
1915                 NULL, LDAP_UTF8_APPROX, NULL );
1916         if( val == NULL || BER_BVISNULL( val ) ) {
1917                 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1918                 BER_BVZERO( &keys[0] );
1919                 *keysp = keys;
1920                 ber_bvfree( val );
1921                 return LDAP_SUCCESS;
1922         }
1923
1924         /* Isolate how many words there are. There will be a key for each */
1925         for( count = 0,c = val->bv_val; *c; c++) {
1926                 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1927                 if( len >= SLAPD_APPROX_WORDLEN ) count++;
1928                 c+= len;
1929                 if (*c == '\0') break;
1930                 *c = '\0';
1931         }
1932
1933         /* Allocate storage for new keys */
1934         keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1935
1936         /* Get a phonetic copy of each word */
1937         for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1938                 len = strlen(c);
1939                 if( len < SLAPD_APPROX_WORDLEN ) continue;
1940                 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1941                 i++;
1942         }
1943
1944         ber_bvfree( val );
1945
1946         BER_BVZERO( &keys[count] );
1947         *keysp = keys;
1948
1949         return LDAP_SUCCESS;
1950 }
1951
1952 /* Remove all spaces and '-' characters */
1953 static int
1954 telephoneNumberNormalize(
1955         slap_mask_t usage,
1956         Syntax *syntax,
1957         MatchingRule *mr,
1958         struct berval *val,
1959         struct berval *normalized,
1960         void *ctx )
1961 {
1962         char *p, *q;
1963
1964         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1965
1966         /* validator should have refused an empty string */
1967         assert( !BER_BVISEMPTY( val ) );
1968
1969         q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
1970
1971         for( p = val->bv_val; *p; p++ ) {
1972                 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1973                         *q++ = *p;
1974                 }
1975         }
1976         *q = '\0';
1977
1978         normalized->bv_len = q - normalized->bv_val;
1979
1980         if( BER_BVISEMPTY( normalized ) ) {
1981                 slap_sl_free( normalized->bv_val, ctx );
1982                 BER_BVZERO( normalized );
1983                 return LDAP_INVALID_SYNTAX;
1984         }
1985
1986         return LDAP_SUCCESS;
1987 }
1988
1989 int
1990 numericoidValidate(
1991         Syntax *syntax,
1992         struct berval *in )
1993 {
1994         struct berval val = *in;
1995
1996         if( BER_BVISEMPTY( &val ) ) {
1997                 /* disallow empty strings */
1998                 return LDAP_INVALID_SYNTAX;
1999         }
2000
2001         while( OID_LEADCHAR( val.bv_val[0] ) ) {
2002                 if ( val.bv_len == 1 ) {
2003                         return LDAP_SUCCESS;
2004                 }
2005
2006                 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2007                         break;
2008                 }
2009
2010                 val.bv_val++;
2011                 val.bv_len--;
2012
2013                 while ( OID_LEADCHAR( val.bv_val[0] )) {
2014                         val.bv_val++;
2015                         val.bv_len--;
2016
2017                         if ( val.bv_len == 0 ) {
2018                                 return LDAP_SUCCESS;
2019                         }
2020                 }
2021
2022                 if( !OID_SEPARATOR( val.bv_val[0] )) {
2023                         break;
2024                 }
2025
2026                 val.bv_val++;
2027                 val.bv_len--;
2028         }
2029
2030         return LDAP_INVALID_SYNTAX;
2031 }
2032
2033 static int
2034 integerValidate(
2035         Syntax *syntax,
2036         struct berval *in )
2037 {
2038         ber_len_t i;
2039         struct berval val = *in;
2040
2041         if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2042
2043         if ( val.bv_val[0] == '-' ) {
2044                 val.bv_len--;
2045                 val.bv_val++;
2046
2047                 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2048                         return LDAP_INVALID_SYNTAX;
2049                 }
2050
2051                 if( val.bv_val[0] == '0' ) { /* "-0" */
2052                         return LDAP_INVALID_SYNTAX;
2053                 }
2054
2055         } else if ( val.bv_val[0] == '0' ) {
2056                 if( val.bv_len > 1 ) { /* "0<more>" */
2057                         return LDAP_INVALID_SYNTAX;
2058                 }
2059
2060                 return LDAP_SUCCESS;
2061         }
2062
2063         for( i=0; i < val.bv_len; i++ ) {
2064                 if( !ASCII_DIGIT(val.bv_val[i]) ) {
2065                         return LDAP_INVALID_SYNTAX;
2066                 }
2067         }
2068
2069         return LDAP_SUCCESS;
2070 }
2071
2072 static int
2073 integerMatch(
2074         int *matchp,
2075         slap_mask_t flags,
2076         Syntax *syntax,
2077         MatchingRule *mr,
2078         struct berval *value,
2079         void *assertedValue )
2080 {
2081         struct berval *asserted = (struct berval *) assertedValue;
2082         int vsign = 1, asign = 1;       /* default sign = '+' */
2083         struct berval v, a;
2084         int match;
2085
2086         v = *value;
2087         if( v.bv_val[0] == '-' ) {
2088                 vsign = -1;
2089                 v.bv_val++;
2090                 v.bv_len--;
2091         }
2092
2093         if( BER_BVISEMPTY( &v ) ) vsign = 0;
2094
2095         a = *asserted;
2096         if( a.bv_val[0] == '-' ) {
2097                 asign = -1;
2098                 a.bv_val++;
2099                 a.bv_len--;
2100         }
2101
2102         if( BER_BVISEMPTY( &a ) ) vsign = 0;
2103
2104         match = vsign - asign;
2105         if( match == 0 ) {
2106                 match = ( v.bv_len != a.bv_len
2107                         ? ( v.bv_len < a.bv_len ? -1 : 1 )
2108                         : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2109                 if( vsign < 0 ) match = -match;
2110         }
2111
2112         *matchp = match;
2113         return LDAP_SUCCESS;
2114 }
2115
2116 /* Index generation function */
2117 static int
2118 integerIndexer(
2119         slap_mask_t use,
2120         slap_mask_t flags,
2121         Syntax *syntax,
2122         MatchingRule *mr,
2123         struct berval *prefix,
2124         BerVarray values,
2125         BerVarray *keysp,
2126         void *ctx )
2127 {
2128         char ibuf[64];
2129         struct berval iv, itmp;
2130         BerVarray keys;
2131         int i, rc;
2132
2133         if ( !index_intlen ) {
2134                 return octetStringIndexer( use, flags, syntax, mr,
2135                         prefix, values, keysp, ctx );
2136         }
2137
2138         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2139                 /* just count them */
2140         }
2141
2142         /* we should have at least one value at this point */
2143         assert( i > 0 );
2144
2145         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2146         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2147                 keys[i].bv_len = index_intlen+1;
2148                 keys[i].bv_val = slap_sl_malloc( index_intlen+1, ctx );
2149         }
2150         keys[i].bv_len = 0;
2151         keys[i].bv_val = NULL;
2152
2153         itmp.bv_val = ibuf;
2154         itmp.bv_len = sizeof(ibuf);
2155
2156         for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2157                 if ( values[i].bv_len > itmp.bv_len ) {
2158                         itmp.bv_len = values[i].bv_len;
2159                         if ( itmp.bv_val == ibuf ) {
2160                                 itmp.bv_val = slap_sl_malloc( itmp.bv_len, ctx );
2161                         } else {
2162                                 itmp.bv_val = slap_sl_realloc( itmp.bv_val, itmp.bv_len, ctx );
2163                         }
2164                 }
2165                 iv = itmp;
2166                 if ( lutil_str2bin( &values[i], &iv )) {
2167                         rc = LDAP_INVALID_SYNTAX;
2168                         goto leave;
2169                 }
2170                 /* If too small, pad with zeros */
2171                 if ( iv.bv_len < index_intlen ) {
2172                         int j, k;
2173                         keys[i].bv_val[0] = index_intlen;
2174                         k = index_intlen - iv.bv_len + 1;
2175                         for ( j=1; j<k; j++)
2176                                 keys[i].bv_val[j] = 0;
2177                         for ( j = 0; j<iv.bv_len; j++ )
2178                                 keys[i].bv_val[j+k] = iv.bv_val[j];
2179                 } else {
2180                         keys[i].bv_val[0] = iv.bv_len;
2181                         memcpy( keys[i].bv_val+1, iv.bv_val, index_intlen );
2182                 }
2183                 /* convert signed to unsigned */
2184                 keys[i].bv_val[1] ^= 0x80;
2185         }
2186         *keysp = keys;
2187         rc = 0;
2188 leave:
2189         if ( itmp.bv_val != ibuf ) {
2190                 slap_sl_free( itmp.bv_val, ctx );
2191         }
2192         return rc;
2193 }
2194
2195 /* Index generation function */
2196 static int
2197 integerFilter(
2198         slap_mask_t use,
2199         slap_mask_t flags,
2200         Syntax *syntax,
2201         MatchingRule *mr,
2202         struct berval *prefix,
2203         void * assertedValue,
2204         BerVarray *keysp,
2205         void *ctx )
2206 {
2207         char ibuf[64];
2208         struct berval iv;
2209         BerVarray keys;
2210         struct berval *value;
2211         int i, rc;
2212
2213         if ( !index_intlen ) {
2214                 return octetStringFilter( use, flags, syntax, mr,
2215                         prefix, assertedValue, keysp, ctx );
2216         }
2217
2218         value = (struct berval *) assertedValue;
2219
2220         keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2221
2222         keys[0].bv_len = index_intlen + 1;
2223         keys[0].bv_val = slap_sl_malloc( index_intlen+1, ctx );
2224
2225         if ( value->bv_len > sizeof( ibuf )) {
2226                 iv.bv_val = slap_sl_malloc( value->bv_len, ctx );
2227                 iv.bv_len = value->bv_len;
2228         } else {
2229                 iv.bv_val = ibuf;
2230                 iv.bv_len = sizeof(ibuf);
2231         }
2232
2233         if ( lutil_str2bin( value, &iv )) {
2234                 rc = LDAP_INVALID_SYNTAX;
2235                 goto leave;
2236         }
2237         /* If too small, pad with zeros */
2238         if ( iv.bv_len < index_intlen ) {
2239                 int j, k;
2240                 keys[0].bv_val[0] = index_intlen;
2241                 k = index_intlen - iv.bv_len + 1;
2242                 for ( j=1; j<k; j++)
2243                         keys[0].bv_val[j] = 0;
2244                 for ( j = 0; j<iv.bv_len; j++ )
2245                         keys[0].bv_val[j+k] = iv.bv_val[j];
2246         } else {
2247                 keys[0].bv_val[0] = iv.bv_len;
2248                 memcpy( keys[0].bv_val+1, iv.bv_val, index_intlen );
2249         }
2250         /* convert signed to unsigned */
2251         keys[0].bv_val[1] ^= 0x80;
2252
2253         rc = 0;
2254         *keysp = keys;
2255 leave:
2256         if ( iv.bv_val != ibuf ) {
2257                 slap_sl_free( iv.bv_val, ctx );
2258         }
2259         return rc;
2260 }
2261
2262 static int
2263 countryStringValidate(
2264         Syntax *syntax,
2265         struct berval *val )
2266 {
2267         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2268
2269         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2270                 return LDAP_INVALID_SYNTAX;
2271         }
2272         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2273                 return LDAP_INVALID_SYNTAX;
2274         }
2275
2276         return LDAP_SUCCESS;
2277 }
2278
2279 static int
2280 printableStringValidate(
2281         Syntax *syntax,
2282         struct berval *val )
2283 {
2284         ber_len_t i;
2285
2286         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2287
2288         for(i=0; i < val->bv_len; i++) {
2289                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2290                         return LDAP_INVALID_SYNTAX;
2291                 }
2292         }
2293
2294         return LDAP_SUCCESS;
2295 }
2296
2297 static int
2298 printablesStringValidate(
2299         Syntax *syntax,
2300         struct berval *val )
2301 {
2302         ber_len_t i, len;
2303
2304         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2305
2306         for(i=0,len=0; i < val->bv_len; i++) {
2307                 int c = val->bv_val[i];
2308
2309                 if( c == '$' ) {
2310                         if( len == 0 ) {
2311                                 return LDAP_INVALID_SYNTAX;
2312                         }
2313                         len = 0;
2314
2315                 } else if ( SLAP_PRINTABLE(c) ) {
2316                         len++;
2317                 } else {
2318                         return LDAP_INVALID_SYNTAX;
2319                 }
2320         }
2321
2322         if( len == 0 ) {
2323                 return LDAP_INVALID_SYNTAX;
2324         }
2325
2326         return LDAP_SUCCESS;
2327 }
2328
2329 static int
2330 IA5StringValidate(
2331         Syntax *syntax,
2332         struct berval *val )
2333 {
2334         ber_len_t i;
2335
2336         for(i=0; i < val->bv_len; i++) {
2337                 if( !LDAP_ASCII(val->bv_val[i]) ) {
2338                         return LDAP_INVALID_SYNTAX;
2339                 }
2340         }
2341
2342         return LDAP_SUCCESS;
2343 }
2344
2345 static int
2346 IA5StringNormalize(
2347         slap_mask_t use,
2348         Syntax *syntax,
2349         MatchingRule *mr,
2350         struct berval *val,
2351         struct berval *normalized,
2352         void *ctx )
2353 {
2354         char *p, *q;
2355         int casefold = !SLAP_MR_ASSOCIATED( mr,
2356                 slap_schema.si_mr_caseExactIA5Match );
2357
2358         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2359
2360         p = val->bv_val;
2361
2362         /* Ignore initial whitespace */
2363         while ( ASCII_SPACE( *p ) ) p++;
2364
2365         normalized->bv_len = val->bv_len - ( p - val->bv_val );
2366         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2367         AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2368         normalized->bv_val[normalized->bv_len] = '\0';
2369
2370         p = q = normalized->bv_val;
2371
2372         while ( *p ) {
2373                 if ( ASCII_SPACE( *p ) ) {
2374                         *q++ = *p++;
2375
2376                         /* Ignore the extra whitespace */
2377                         while ( ASCII_SPACE( *p ) ) {
2378                                 p++;
2379                         }
2380
2381                 } else if ( casefold ) {
2382                         /* Most IA5 rules require casefolding */
2383                         *q++ = TOLOWER(*p); p++;
2384
2385                 } else {
2386                         *q++ = *p++;
2387                 }
2388         }
2389
2390         assert( normalized->bv_val <= p );
2391         assert( q <= p );
2392
2393         /*
2394          * If the string ended in space, backup the pointer one
2395          * position.  One is enough because the above loop collapsed
2396          * all whitespace to a single space.
2397          */
2398         if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2399
2400         /* null terminate */
2401         *q = '\0';
2402
2403         normalized->bv_len = q - normalized->bv_val;
2404
2405         return LDAP_SUCCESS;
2406 }
2407
2408 static int
2409 UUIDValidate(
2410         Syntax *syntax,
2411         struct berval *in )
2412 {
2413         int i;
2414         if( in->bv_len != 36 ) {
2415                 return LDAP_INVALID_SYNTAX;
2416         }
2417
2418         for( i=0; i<36; i++ ) {
2419                 switch(i) {
2420                         case 8:
2421                         case 13:
2422                         case 18:
2423                         case 23:
2424                                 if( in->bv_val[i] != '-' ) {
2425                                         return LDAP_INVALID_SYNTAX;
2426                                 }
2427                                 break;
2428                         default:
2429                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2430                                         return LDAP_INVALID_SYNTAX;
2431                                 }
2432                 }
2433         }
2434         
2435         return LDAP_SUCCESS;
2436 }
2437
2438 static int
2439 UUIDPretty(
2440         Syntax *syntax,
2441         struct berval *in,
2442         struct berval *out,
2443         void *ctx )
2444 {
2445         int i;
2446         int rc=LDAP_INVALID_SYNTAX;
2447
2448         assert( in != NULL );
2449         assert( out != NULL );
2450
2451         if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2452
2453         out->bv_len = 36;
2454         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2455
2456         for( i=0; i<36; i++ ) {
2457                 switch(i) {
2458                         case 8:
2459                         case 13:
2460                         case 18:
2461                         case 23:
2462                                 if( in->bv_val[i] != '-' ) {
2463                                         goto handle_error;
2464                                 }
2465                                 out->bv_val[i] = '-';
2466                                 break;
2467
2468                         default:
2469                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2470                                         goto handle_error;
2471                                 }
2472                                 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2473                 }
2474         }
2475
2476         rc = LDAP_SUCCESS;
2477         out->bv_val[ out->bv_len ] = '\0';
2478
2479         if( 0 ) {
2480 handle_error:
2481                 slap_sl_free( out->bv_val, ctx );
2482                 out->bv_val = NULL;
2483         }
2484
2485         return rc;
2486 }
2487
2488 int
2489 UUIDNormalize(
2490         slap_mask_t usage,
2491         Syntax *syntax,
2492         MatchingRule *mr,
2493         struct berval *val,
2494         struct berval *normalized,
2495         void *ctx )
2496 {
2497         unsigned char octet = '\0';
2498         int i;
2499         int j;
2500
2501         if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
2502                 /* NOTE: must be a normalized UUID */
2503                 assert( val->bv_len == 16 );
2504
2505                 normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
2506                 normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
2507                         val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
2508                 assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
2509
2510                 return LDAP_SUCCESS;
2511         }
2512
2513         normalized->bv_len = 16;
2514         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2515
2516         for( i=0, j=0; i<36; i++ ) {
2517                 unsigned char nibble;
2518                 if( val->bv_val[i] == '-' ) {
2519                         continue;
2520
2521                 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2522                         nibble = val->bv_val[i] - '0';
2523
2524                 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2525                         nibble = val->bv_val[i] - ('a'-10);
2526
2527                 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2528                         nibble = val->bv_val[i] - ('A'-10);
2529
2530                 } else {
2531                         slap_sl_free( normalized->bv_val, ctx );
2532                         return LDAP_INVALID_SYNTAX;
2533                 }
2534
2535                 if( j & 1 ) {
2536                         octet |= nibble;
2537                         normalized->bv_val[j>>1] = octet;
2538                 } else {
2539                         octet = nibble << 4;
2540                 }
2541                 j++;
2542         }
2543
2544         normalized->bv_val[normalized->bv_len] = 0;
2545         return LDAP_SUCCESS;
2546 }
2547
2548
2549
2550 int
2551 numericStringValidate(
2552         Syntax *syntax,
2553         struct berval *in )
2554 {
2555         ber_len_t i;
2556
2557         if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2558
2559         for(i=0; i < in->bv_len; i++) {
2560                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2561                         return LDAP_INVALID_SYNTAX;
2562                 }
2563         }
2564
2565         return LDAP_SUCCESS;
2566 }
2567
2568 static int
2569 numericStringNormalize(
2570         slap_mask_t usage,
2571         Syntax *syntax,
2572         MatchingRule *mr,
2573         struct berval *val,
2574         struct berval *normalized,
2575         void *ctx )
2576 {
2577         /* removal all spaces */
2578         char *p, *q;
2579
2580         assert( !BER_BVISEMPTY( val ) );
2581
2582         normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2583
2584         p = val->bv_val;
2585         q = normalized->bv_val;
2586
2587         while ( *p ) {
2588                 if ( ASCII_SPACE( *p ) ) {
2589                         /* Ignore whitespace */
2590                         p++;
2591                 } else {
2592                         *q++ = *p++;
2593                 }
2594         }
2595
2596         /* we should have copied no more than is in val */
2597         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2598
2599         /* null terminate */
2600         *q = '\0';
2601
2602         normalized->bv_len = q - normalized->bv_val;
2603
2604         if( BER_BVISEMPTY( normalized ) ) {
2605                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2606                 normalized->bv_val[0] = ' ';
2607                 normalized->bv_val[1] = '\0';
2608                 normalized->bv_len = 1;
2609         }
2610
2611         return LDAP_SUCCESS;
2612 }
2613
2614 /*
2615  * Integer conversion macros that will use the largest available
2616  * type.
2617  */
2618 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
2619 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
2620 # define SLAP_LONG           long long
2621 #else
2622 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
2623 # define SLAP_LONG           long
2624 #endif /* HAVE_STRTOLL ... */
2625
2626 static int
2627 integerBitAndMatch(
2628         int *matchp,
2629         slap_mask_t flags,
2630         Syntax *syntax,
2631         MatchingRule *mr,
2632         struct berval *value,
2633         void *assertedValue )
2634 {
2635         SLAP_LONG lValue, lAssertedValue;
2636
2637         errno = 0;
2638         /* safe to assume integers are NUL terminated? */
2639         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2640         if( errno == ERANGE )
2641         {
2642                 return LDAP_CONSTRAINT_VIOLATION;
2643         }
2644
2645         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2646                 NULL, 10);
2647         if( errno == ERANGE )
2648         {
2649                 return LDAP_CONSTRAINT_VIOLATION;
2650         }
2651
2652         *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2653         return LDAP_SUCCESS;
2654 }
2655
2656 static int
2657 integerBitOrMatch(
2658         int *matchp,
2659         slap_mask_t flags,
2660         Syntax *syntax,
2661         MatchingRule *mr,
2662         struct berval *value,
2663         void *assertedValue )
2664 {
2665         SLAP_LONG lValue, lAssertedValue;
2666
2667         errno = 0;
2668         /* safe to assume integers are NUL terminated? */
2669         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2670         if( errno == ERANGE )
2671         {
2672                 return LDAP_CONSTRAINT_VIOLATION;
2673         }
2674
2675         lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2676                 NULL, 10);
2677         if( errno == ERANGE )
2678         {
2679                 return LDAP_CONSTRAINT_VIOLATION;
2680         }
2681
2682         *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2683         return LDAP_SUCCESS;
2684 }
2685
2686 static int
2687 serialNumberAndIssuerCheck(
2688         struct berval *in,
2689         struct berval *sn,
2690         struct berval *is,
2691         void *ctx
2692 )
2693 {
2694         int is_hex = 0, n;
2695
2696         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2697
2698         if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2699                 /* Parse old format */
2700                 is->bv_val = ber_bvchr( in, '$' );
2701                 if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
2702
2703                 sn->bv_val = in->bv_val;
2704                 sn->bv_len = is->bv_val - in->bv_val;
2705
2706                 is->bv_val++;
2707                 is->bv_len = in->bv_len - (sn->bv_len + 1);
2708
2709                 /* eat leading zeros */
2710                 for( n=0; n < (sn->bv_len-1); n++ ) {
2711                         if( sn->bv_val[n] != '0' ) break;
2712                 }
2713                 sn->bv_val += n;
2714                 sn->bv_len -= n;
2715
2716                 for( n=0; n < sn->bv_len; n++ ) {
2717                         if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2718                 }
2719
2720         } else {
2721                 /* Parse GSER format */ 
2722                 int havesn=0,haveissuer=0;
2723                 struct berval x = *in;
2724                 struct berval ni;
2725                 x.bv_val++;
2726                 x.bv_len-=2;
2727
2728                 /* eat leading spaces */
2729                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2730                         /* empty */;
2731                 }
2732
2733                 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2734                         return LDAP_INVALID_SYNTAX;
2735                 }
2736
2737                 /* should be at issuer or serialNumber NamedValue */
2738                 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2739                         /* parse issuer */
2740                         x.bv_val += STRLENOF("issuer");
2741                         x.bv_len -= STRLENOF("issuer");
2742
2743                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2744                         x.bv_val++; x.bv_len--;
2745
2746                         /* eat leading spaces */
2747                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2748                                 /* empty */;
2749                         }
2750
2751                         /* For backward compatibility, this part is optional */
2752                         if( !strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:"))) {
2753                                 x.bv_val += STRLENOF("rdnSequence:");
2754                                 x.bv_len -= STRLENOF("rdnSequence:");
2755                         }
2756
2757                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2758                         x.bv_val++; x.bv_len--;
2759
2760                         is->bv_val = x.bv_val;
2761                         is->bv_len = 0;
2762
2763                         for( ; is->bv_len < x.bv_len; ) {
2764                                 if ( is->bv_val[is->bv_len] != '"' ) {
2765                                         is->bv_len++;
2766                                         continue;
2767                                 }
2768                                 if ( is->bv_val[is->bv_len+1] == '"' ) {
2769                                         /* double dquote */
2770                                         is->bv_len+=2;
2771                                         continue;
2772                                 }
2773                                 break;
2774                         }
2775                         x.bv_val += is->bv_len+1;
2776                         x.bv_len -= is->bv_len+1;
2777
2778                         if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2779                                 return LDAP_INVALID_SYNTAX;
2780                         }
2781
2782                         haveissuer++;
2783
2784                 } else if( strncasecmp( x.bv_val, "serialNumber",
2785                         STRLENOF("serialNumber")) == 0 )
2786                 {
2787                         /* parse serialNumber */
2788                         int neg=0;
2789                         x.bv_val += STRLENOF("serialNumber");
2790                         x.bv_len -= STRLENOF("serialNumber");
2791
2792                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2793                         x.bv_val++; x.bv_len--;
2794
2795                         /* eat leading spaces */
2796                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2797                                 /* empty */;
2798                         }
2799                         
2800                         sn->bv_val = x.bv_val;
2801                         sn->bv_len = 0;
2802
2803                         if( sn->bv_val[0] == '-' ) {
2804                                 neg++;
2805                                 sn->bv_len++;
2806                         }
2807
2808                         if ( sn->bv_val[0] == '0' && ( sn->bv_val[1] == 'x' ||
2809                                 sn->bv_val[1] == 'X' )) {
2810                                 is_hex = 1;
2811                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2812                                         if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2813                                 }
2814                         } else if ( sn->bv_val[0] == '\'' ) {
2815                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2816                                         if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2817                                 }
2818                                 if ( sn->bv_val[sn->bv_len] == '\'' &&
2819                                         sn->bv_val[sn->bv_len+1] == 'H' )
2820                                         is_hex = 1;
2821                                 else
2822                                         return LDAP_INVALID_SYNTAX;
2823                                 sn->bv_len += 2;
2824                         } else {
2825                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2826                                         if ( !ASCII_DIGIT( sn->bv_val[sn->bv_len] )) break;
2827                                 }
2828                         }
2829
2830                         if (!( sn->bv_len > neg )) return LDAP_INVALID_SYNTAX;
2831                         if (( sn->bv_len > 1+neg ) && ( sn->bv_val[neg] == '0' )) {
2832                                 return LDAP_INVALID_SYNTAX;
2833                         }
2834
2835                         x.bv_val += sn->bv_len; x.bv_len -= sn->bv_len;
2836
2837                         if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2838                                 return LDAP_INVALID_SYNTAX;
2839                         }
2840
2841                         havesn++;
2842
2843                 } else return LDAP_INVALID_SYNTAX;
2844
2845                 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2846                 x.bv_val++; x.bv_len--;
2847
2848                 /* eat spaces */
2849                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2850                         /* empty */;
2851                 }
2852
2853                 /* should be at remaining NamedValue */
2854                 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2855                         STRLENOF("issuer" )) == 0 ))
2856                 {
2857                         /* parse issuer */
2858                         x.bv_val += STRLENOF("issuer");
2859                         x.bv_len -= STRLENOF("issuer");
2860
2861                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2862                         x.bv_val++; x.bv_len--;
2863
2864                         /* eat leading spaces */
2865                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2866                                  /* empty */;
2867                         }
2868
2869                         /* For backward compatibility, this part is optional */
2870                         if( !strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:"))) {
2871                                 x.bv_val += STRLENOF("rdnSequence:");
2872                                 x.bv_len -= STRLENOF("rdnSequence:");
2873                         }
2874
2875                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2876                         x.bv_val++; x.bv_len--;
2877
2878                         is->bv_val = x.bv_val;
2879                         is->bv_len = 0;
2880
2881                         for( ; is->bv_len < x.bv_len; ) {
2882                                 if ( is->bv_val[is->bv_len] != '"' ) {
2883                                         is->bv_len++;
2884                                         continue;
2885                                 }
2886                                 if ( is->bv_val[is->bv_len+1] == '"' ) {
2887                                         /* double dquote */
2888                                         is->bv_len+=2;
2889                                         continue;
2890                                 }
2891                                 break;
2892                         }
2893                         x.bv_val += is->bv_len+1;
2894                         x.bv_len -= is->bv_len+1;
2895
2896                 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2897                         STRLENOF("serialNumber")) == 0 ))
2898                 {
2899                         /* parse serialNumber */
2900                         int neg=0;
2901                         x.bv_val += STRLENOF("serialNumber");
2902                         x.bv_len -= STRLENOF("serialNumber");
2903
2904                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2905                         x.bv_val++; x.bv_len--;
2906
2907                         /* eat leading spaces */
2908                         for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2909                                 /* empty */;
2910                         }
2911                         
2912                         sn->bv_val = x.bv_val;
2913                         sn->bv_len = 0;
2914
2915                         if( sn->bv_val[0] == '-' ) {
2916                                 neg++;
2917                                 sn->bv_len++;
2918                         }
2919
2920                         if ( sn->bv_val[0] == '0' && ( sn->bv_val[1] == 'x' ||
2921                                 sn->bv_val[1] == 'X' )) {
2922                                 is_hex = 1;
2923                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2924                                         if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2925                                 }
2926                         } else if ( sn->bv_val[0] == '\'' ) {
2927                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2928                                         if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2929                                 }
2930                                 if ( sn->bv_val[sn->bv_len] == '\'' &&
2931                                         sn->bv_val[sn->bv_len+1] == 'H' )
2932                                         is_hex = 1;
2933                                 else
2934                                         return LDAP_INVALID_SYNTAX;
2935                                 sn->bv_len += 2;
2936                         } else {
2937                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2938                                         if ( !ASCII_DIGIT( sn->bv_val[sn->bv_len] )) break;
2939                                 }
2940                         }
2941
2942                         if (!( sn->bv_len > neg )) return LDAP_INVALID_SYNTAX;
2943                         if (( sn->bv_len > 1+neg ) && ( sn->bv_val[neg] == '0' )) {
2944                                 return LDAP_INVALID_SYNTAX;
2945                         }
2946
2947                         x.bv_val += sn->bv_len;
2948                         x.bv_len -= sn->bv_len;
2949
2950                 } else return LDAP_INVALID_SYNTAX;
2951
2952                 /* eat trailing spaces */
2953                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2954                         /* empty */;
2955                 }
2956
2957                 /* should have no characters left... */
2958                 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
2959
2960                 ber_dupbv_x( &ni, is, ctx );
2961                 *is = ni;
2962
2963                 /* need to handle double dquotes here */
2964         }
2965         return 0;
2966 }
2967         
2968 static int
2969 serialNumberAndIssuerValidate(
2970         Syntax *syntax,
2971         struct berval *in )
2972 {
2973         int rc;
2974         struct berval sn, i;
2975
2976         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
2977                 in->bv_val, 0, 0 );
2978
2979         rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
2980         if ( rc )
2981                 return rc;
2982
2983         /* validate DN -- doesn't handle double dquote */ 
2984         rc = dnValidate( NULL, &i );
2985         if( rc )
2986                 rc = LDAP_INVALID_SYNTAX;
2987
2988         if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
2989                 slap_sl_free( i.bv_val, NULL );
2990         }
2991
2992         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: OKAY\n",
2993                 0, 0, 0 );
2994         return rc;
2995 }
2996
2997 int
2998 serialNumberAndIssuerPretty(
2999         Syntax *syntax,
3000         struct berval *in,
3001         struct berval *out,
3002         void *ctx )
3003 {
3004         int n, rc;
3005         struct berval sn, i, ni;
3006
3007         assert( in != NULL );
3008         assert( out != NULL );
3009
3010         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3011                 in->bv_val, 0, 0 );
3012
3013         rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3014         if ( rc )
3015                 return rc;
3016
3017         rc = dnPretty( syntax, &i, &ni, ctx );
3018
3019         if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3020                 slap_sl_free( i.bv_val, ctx );
3021         }
3022
3023         if( rc ) return LDAP_INVALID_SYNTAX;
3024
3025         /* make room from sn + "$" */
3026         out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3027                 + sn.bv_len + ni.bv_len;
3028         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3029
3030         if( out->bv_val == NULL ) {
3031                 out->bv_len = 0;
3032                 slap_sl_free( ni.bv_val, ctx );
3033                 return LDAP_OTHER;
3034         }
3035
3036         n = 0;
3037         AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3038                 STRLENOF("{ serialNumber "));
3039         n = STRLENOF("{ serialNumber ");
3040
3041         AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3042         n += sn.bv_len;
3043
3044         AC_MEMCPY( &out->bv_val[n], ", issuer rdnSequence:\"", STRLENOF(", issuer rdnSequence:\""));
3045         n += STRLENOF(", issuer rdnSequence:\"");
3046
3047         AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3048         n += ni.bv_len;
3049
3050         AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF("\" }"));
3051         n += STRLENOF("\" }");
3052
3053         out->bv_val[n] = '\0';
3054
3055         assert( n == out->bv_len );
3056
3057         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
3058                 out->bv_val, 0, 0 );
3059
3060         slap_sl_free( ni.bv_val, ctx );
3061
3062         return LDAP_SUCCESS; 
3063 }
3064
3065 /*
3066  * This routine is called by certificateExactNormalize when
3067  * certificateExactNormalize receives a search string instead of
3068  * a certificate. This routine checks if the search value is valid
3069  * and then returns the normalized value
3070  */
3071 static int
3072 serialNumberAndIssuerNormalize(
3073         slap_mask_t usage,
3074         Syntax *syntax,
3075         MatchingRule *mr,
3076         struct berval *in,
3077         struct berval *out,
3078         void *ctx )
3079 {
3080         struct berval sn, sn2, i, ni;
3081         char sbuf[64], *stmp = sbuf;
3082         int rc;
3083         ber_len_t n;
3084         int is_hex = 0;
3085
3086         assert( in != NULL );
3087         assert( out != NULL );
3088
3089         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3090                 in->bv_val, 0, 0 );
3091
3092         rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3093         if ( rc )
3094                 return rc;
3095
3096         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3097
3098         if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3099                 slap_sl_free( i.bv_val, ctx );
3100         }
3101
3102         if( rc ) return LDAP_INVALID_SYNTAX;
3103
3104         /* Convert sn to canonical hex */
3105         if ( sn.bv_len > sizeof( sbuf )) {
3106                 stmp = slap_sl_malloc( sn.bv_len, ctx );
3107         }
3108         sn2.bv_val = stmp;
3109         sn2.bv_len = sn.bv_len;
3110         if ( lutil_str2bin( &sn, &sn2 )) {
3111                 rc = LDAP_INVALID_SYNTAX;
3112                 goto leave;
3113         }
3114
3115         /* make room for sn + "$" */
3116         out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3117                 + ( sn2.bv_len * 2 + 3 ) + ni.bv_len;
3118         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3119
3120         if( out->bv_val == NULL ) {
3121                 out->bv_len = 0;
3122                 slap_sl_free( ni.bv_val, ctx );
3123                 rc = LDAP_OTHER;
3124                 goto leave;
3125         }
3126
3127         n = 0;
3128         AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3129                 STRLENOF( "{ serialNumber " ));
3130         n = STRLENOF( "{ serialNumber " );
3131
3132         AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3133         {
3134                 int j;
3135                 unsigned char *v = sn2.bv_val;
3136                 out->bv_val[n++] = '\'';
3137                 for ( j = 0; j < sn2.bv_len; j++ ) {
3138                         sprintf( &out->bv_val[n], "%02X", v[j] );
3139                         n += 2;
3140                 }
3141                 out->bv_val[n++] = '\'';
3142                 out->bv_val[n++] = 'H';
3143         }
3144
3145         AC_MEMCPY( &out->bv_val[n], ", issuer rdnSequence:\"", STRLENOF( ", issuer rdnSequence:\"" ));
3146         n += STRLENOF( ", issuer rdnSequence:\"" );
3147
3148         AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3149         n += ni.bv_len;
3150
3151         AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF( "\" }" ));
3152         n += STRLENOF( "\" }" );
3153
3154         out->bv_val[n] = '\0';
3155
3156         assert( n == out->bv_len );
3157
3158         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
3159                 out->bv_val, 0, 0 );
3160
3161 leave:
3162         if ( stmp != sbuf )
3163                 slap_sl_free( stmp, ctx );
3164         slap_sl_free( ni.bv_val, ctx );
3165
3166         return rc;
3167 }
3168
3169 static int
3170 certificateExactNormalize(
3171         slap_mask_t usage,
3172         Syntax *syntax,
3173         MatchingRule *mr,
3174         struct berval *val,
3175         struct berval *normalized,
3176         void *ctx )
3177 {
3178         BerElementBuffer berbuf;
3179         BerElement *ber = (BerElement *)&berbuf;
3180         ber_tag_t tag;
3181         ber_len_t len;
3182         ber_int_t i;
3183         char serialbuf[64], *serial = serialbuf;
3184         ber_len_t seriallen;
3185         struct berval issuer_dn = BER_BVNULL, bvdn;
3186         unsigned char *p;
3187         int rc = LDAP_INVALID_SYNTAX;
3188
3189         if( BER_BVISEMPTY( val ) ) goto done;
3190
3191         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3192                 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
3193         }
3194
3195         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3196
3197         ber_init2( ber, val, LBER_USE_DER );
3198         tag = ber_skip_tag( ber, &len );        /* Signed Sequence */
3199         tag = ber_skip_tag( ber, &len );        /* Sequence */
3200         tag = ber_peek_tag( ber, &len );        /* Optional version? */
3201         if ( tag == SLAP_X509_OPT_C_VERSION ) {
3202                 tag = ber_skip_tag( ber, &len );
3203                 tag = ber_get_int( ber, &i );   /* version */
3204         }
3205
3206         /* NOTE: move the test here from certificateValidate,
3207          * so that we can validate certs with serial longer
3208          * than sizeof(ber_int_t) */
3209         tag = ber_peek_tag( ber, &len );        /* serial */
3210
3211         /* Use hex format. '123456789abcdef'H
3212          */
3213         {
3214                 unsigned char *ptr;
3215                 char *sptr;
3216                 
3217                 tag = ber_skip_tag( ber, &len );
3218                 ptr = (unsigned char *)ber->ber_ptr;
3219                 ber_skip_data( ber, len );
3220
3221                 /* Check for minimal encodings */
3222                 if ( len > 1 ) {
3223                         if ( ptr[0] & 0x80 ) {
3224                                 if (( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ))
3225                                         return LDAP_INVALID_SYNTAX;
3226                         } else if ( ptr[0] == 0 ) {
3227                                 if (!( ptr[1] & 0x80 ))
3228                                         return LDAP_INVALID_SYNTAX;
3229                         }
3230                 }
3231
3232                 seriallen = len * 2 + 4;        /* quotes, H, NUL */
3233                 if ( seriallen > sizeof( serialbuf ))
3234                         serial = slap_sl_malloc( seriallen, ctx );
3235                 sptr = serial;
3236                 *sptr++ = '\'';
3237                 for ( i = 0; i<len; i++ ) {
3238                         sprintf( sptr, "%02X", ptr[i] );
3239                         sptr += 2;
3240                 }
3241                 *sptr++ = '\'';
3242                 *sptr++ = 'H';
3243                 seriallen--;
3244         }
3245         tag = ber_skip_tag( ber, &len );        /* SignatureAlg */
3246         ber_skip_data( ber, len );
3247         tag = ber_peek_tag( ber, &len );        /* IssuerDN */
3248         len = ber_ptrlen( ber );
3249         bvdn.bv_val = val->bv_val + len;
3250         bvdn.bv_len = val->bv_len - len;
3251
3252         rc = dnX509normalize( &bvdn, &issuer_dn );
3253         if( rc != LDAP_SUCCESS ) goto done;
3254
3255         normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3256                 + seriallen + issuer_dn.bv_len;
3257         normalized->bv_val = ch_malloc(normalized->bv_len+1);
3258
3259         p = (unsigned char *)normalized->bv_val;
3260
3261         AC_MEMCPY(p, "{ serialNumber ", STRLENOF( "{ serialNumber " ));
3262         p += STRLENOF( "{ serialNumber " );
3263
3264         AC_MEMCPY(p, serial, seriallen);
3265         p += seriallen;
3266
3267         AC_MEMCPY(p, ", issuer rdnSequence:\"", STRLENOF( ", issuer rdnSequence:\"" ));
3268         p += STRLENOF( ", issuer rdnSequence:\"" );
3269
3270         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
3271         p += issuer_dn.bv_len;
3272
3273         AC_MEMCPY(p, "\" }", STRLENOF( "\" }" ));
3274         p += STRLENOF( "\" }" );
3275
3276         *p = '\0';
3277
3278         Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
3279                 normalized->bv_val, NULL, NULL );
3280
3281         rc = LDAP_SUCCESS;
3282
3283 done:
3284         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3285         if ( serial != serialbuf ) ber_memfree_x( serial, ctx );
3286
3287         return rc;
3288 }
3289
3290 static int
3291 hexValidate(
3292         Syntax *syntax,
3293         struct berval *in )
3294 {
3295         int     i;
3296
3297         assert( in != NULL );
3298         assert( !BER_BVISNULL( in ) );
3299
3300         for ( i = 0; i < in->bv_len; i++ ) {
3301                 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
3302                         return LDAP_INVALID_SYNTAX;
3303                 }
3304         }
3305
3306         return LDAP_SUCCESS;
3307 }
3308
3309 /* Normalize a SID as used inside a CSN:
3310  * three-digit numeric string */
3311 static int
3312 hexNormalize(
3313         slap_mask_t usage,
3314         Syntax *syntax,
3315         MatchingRule *mr,
3316         struct berval *val,
3317         struct berval *normalized,
3318         void *ctx )
3319 {
3320         int     i;
3321
3322         assert( val != NULL );
3323         assert( normalized != NULL );
3324
3325         ber_dupbv_x( normalized, val, ctx );
3326
3327         for ( i = 0; i < normalized->bv_len; i++ ) {
3328                 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
3329                         ber_memfree_x( normalized->bv_val, ctx );
3330                         BER_BVZERO( normalized );
3331                         return LDAP_INVALID_SYNTAX;
3332                 }
3333
3334                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3335         }
3336
3337         return LDAP_SUCCESS;
3338 }
3339
3340 static int
3341 sidValidate (
3342         Syntax *syntax,
3343         struct berval *in )
3344 {
3345         assert( in != NULL );
3346         assert( !BER_BVISNULL( in ) );
3347
3348         if ( in->bv_len != 3 ) {
3349                 return LDAP_INVALID_SYNTAX;
3350         }
3351
3352         return hexValidate( NULL, in );
3353 }
3354
3355 /* Normalize a SID as used inside a CSN:
3356  * three-digit numeric string */
3357 static int
3358 sidNormalize(
3359         slap_mask_t usage,
3360         Syntax *syntax,
3361         MatchingRule *mr,
3362         struct berval *val,
3363         struct berval *normalized,
3364         void *ctx )
3365 {
3366         if ( val->bv_len != 3 ) {
3367                 return LDAP_INVALID_SYNTAX;
3368         }
3369
3370         return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
3371 }
3372
3373 static int
3374 sidPretty(
3375         Syntax *syntax,
3376         struct berval *val,
3377         struct berval *out,
3378         void *ctx )
3379 {
3380         return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3381 }
3382
3383 /* Normalize a SID as used inside a CSN, either as-is
3384  * (assertion value) or extracted from the CSN
3385  * (attribute value) */
3386 static int
3387 csnSidNormalize(
3388         slap_mask_t usage,
3389         Syntax *syntax,
3390         MatchingRule *mr,
3391         struct berval *val,
3392         struct berval *normalized,
3393         void *ctx )
3394 {
3395         struct berval   bv;
3396         char            *ptr,
3397                         buf[ 4 ];
3398
3399
3400         if ( BER_BVISEMPTY( val ) ) {
3401                 return LDAP_INVALID_SYNTAX;
3402         }
3403
3404         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3405                 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
3406         }
3407
3408         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3409
3410         ptr = ber_bvchr( val, '#' );
3411         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3412                 return LDAP_INVALID_SYNTAX;
3413         }
3414
3415         bv.bv_val = ptr + 1;
3416         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3417
3418         ptr = ber_bvchr( &bv, '#' );
3419         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3420                 return LDAP_INVALID_SYNTAX;
3421         }
3422
3423         bv.bv_val = ptr + 1;
3424         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3425                 
3426         ptr = ber_bvchr( &bv, '#' );
3427         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3428                 return LDAP_INVALID_SYNTAX;
3429         }
3430
3431         bv.bv_len = ptr - bv.bv_val;
3432
3433         if ( bv.bv_len == 2 ) {
3434                 /* OpenLDAP 2.3 SID */
3435                 buf[ 0 ] = '0';
3436                 buf[ 1 ] = bv.bv_val[ 0 ];
3437                 buf[ 2 ] = bv.bv_val[ 1 ];
3438                 buf[ 3 ] = '\0';
3439
3440                 bv.bv_val = buf;
3441                 bv.bv_len = 3;
3442         }
3443
3444         return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
3445 }
3446
3447 static int
3448 csnValidate(
3449         Syntax *syntax,
3450         struct berval *in )
3451 {
3452         struct berval   bv;
3453         char            *ptr;
3454         int             rc;
3455
3456         assert( in != NULL );
3457         assert( !BER_BVISNULL( in ) );
3458
3459         if ( BER_BVISEMPTY( in ) ) {
3460                 return LDAP_INVALID_SYNTAX;
3461         }
3462
3463         bv = *in;
3464
3465         ptr = ber_bvchr( &bv, '#' );
3466         if ( ptr == NULL || ptr - bv.bv_val == bv.bv_len ) {
3467                 return LDAP_INVALID_SYNTAX;
3468         }
3469
3470         bv.bv_len = ptr - bv.bv_val;
3471         if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
3472                 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
3473         {
3474                 return LDAP_INVALID_SYNTAX;
3475         }
3476
3477         rc = generalizedTimeValidate( NULL, &bv );
3478         if ( rc != LDAP_SUCCESS ) {
3479                 return rc;
3480         }
3481
3482         bv.bv_val = ptr + 1;
3483         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3484
3485         ptr = ber_bvchr( &bv, '#' );
3486         if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3487                 return LDAP_INVALID_SYNTAX;
3488         }
3489
3490         bv.bv_len = ptr - bv.bv_val;
3491         if ( bv.bv_len != 6 ) {
3492                 return LDAP_INVALID_SYNTAX;
3493         }
3494
3495         rc = hexValidate( NULL, &bv );
3496         if ( rc != LDAP_SUCCESS ) {
3497                 return rc;
3498         }
3499
3500         bv.bv_val = ptr + 1;
3501         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3502
3503         ptr = ber_bvchr( &bv, '#' );
3504         if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3505                 return LDAP_INVALID_SYNTAX;
3506         }
3507
3508         bv.bv_len = ptr - bv.bv_val;
3509         if ( bv.bv_len == 2 ) {
3510                 /* tolerate old 2-digit replica-id */
3511                 rc = hexValidate( NULL, &bv );
3512
3513         } else {
3514                 rc = sidValidate( NULL, &bv );
3515         }
3516         if ( rc != LDAP_SUCCESS ) {
3517                 return rc;
3518         }
3519
3520         bv.bv_val = ptr + 1;
3521         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3522
3523         if ( bv.bv_len != 6 ) {
3524                 return LDAP_INVALID_SYNTAX;
3525         }
3526
3527         return hexValidate( NULL, &bv );
3528 }
3529
3530 /* Normalize a CSN in OpenLDAP 2.3 format */
3531 static int
3532 csnNormalize23(
3533         slap_mask_t usage,
3534         Syntax *syntax,
3535         MatchingRule *mr,
3536         struct berval *val,
3537         struct berval *normalized,
3538         void *ctx )
3539 {
3540         struct berval   gt, cnt, sid, mod;
3541         char            *ptr;
3542         int             i;
3543
3544         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3545         assert( !BER_BVISEMPTY( val ) );
3546
3547         gt = *val;
3548
3549         ptr = ber_bvchr( &gt, '#' );
3550         if ( ptr == NULL || ptr - gt.bv_val == gt.bv_len ) {
3551                 return LDAP_INVALID_SYNTAX;
3552         }
3553
3554         gt.bv_len = ptr - gt.bv_val;
3555         assert( gt.bv_len == STRLENOF( "YYYYmmddHHMMSSZ" ) );
3556
3557         cnt.bv_val = ptr + 1;
3558         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3559
3560         ptr = ber_bvchr( &cnt, '#' );
3561         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3562                 return LDAP_INVALID_SYNTAX;
3563         }
3564
3565         cnt.bv_len = ptr - cnt.bv_val;
3566         assert( cnt.bv_len == STRLENOF( "000000" ) );
3567
3568         sid.bv_val = ptr + 1;
3569         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3570                 
3571         ptr = ber_bvchr( &sid, '#' );
3572         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3573                 return LDAP_INVALID_SYNTAX;
3574         }
3575
3576         sid.bv_len = ptr - sid.bv_val;
3577         assert( sid.bv_len == STRLENOF( "00" ) );
3578
3579         mod.bv_val = ptr + 1;
3580         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3581         assert( mod.bv_len == STRLENOF( "000000" ) );
3582
3583         normalized->bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
3584         normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
3585
3586         ptr = normalized->bv_val;
3587         ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
3588         ptr = lutil_strcopy( ptr, ".000000Z#" );
3589         ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
3590         *ptr++ = '#';
3591         *ptr++ = '0';
3592         for ( i = 0; i < sid.bv_len; i++ ) {
3593                 *ptr++ = TOLOWER( sid.bv_val[ i ] );
3594         }
3595         *ptr++ = '#';
3596         for ( i = 0; i < mod.bv_len; i++ ) {
3597                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
3598         }
3599         *ptr = '\0';
3600
3601         assert( ptr - normalized->bv_val == normalized->bv_len );
3602
3603         return LDAP_SUCCESS;
3604 }
3605
3606 /* Normalize a CSN */
3607 static int
3608 csnNormalize(
3609         slap_mask_t usage,
3610         Syntax *syntax,
3611         MatchingRule *mr,
3612         struct berval *val,
3613         struct berval *normalized,
3614         void *ctx )
3615 {
3616         struct berval   cnt, sid, mod;
3617         char            *ptr;
3618         int             i;
3619
3620         assert( val != NULL );
3621         assert( normalized != NULL );
3622
3623         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3624
3625         if ( BER_BVISEMPTY( val ) ) {
3626                 return LDAP_INVALID_SYNTAX;
3627         }
3628
3629         if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
3630                 /* Openldap <= 2.3 */
3631
3632                 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
3633         }
3634
3635         assert( val->bv_len == STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) );
3636
3637         ptr = ber_bvchr( val, '#' );
3638         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3639                 return LDAP_INVALID_SYNTAX;
3640         }
3641
3642         assert( ptr - val->bv_val == STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) );
3643
3644         cnt.bv_val = ptr + 1;
3645         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3646
3647         ptr = ber_bvchr( &cnt, '#' );
3648         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3649                 return LDAP_INVALID_SYNTAX;
3650         }
3651
3652         assert( ptr - cnt.bv_val == STRLENOF( "000000" ) );
3653
3654         sid.bv_val = ptr + 1;
3655         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3656                 
3657         ptr = ber_bvchr( &sid, '#' );
3658         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3659                 return LDAP_INVALID_SYNTAX;
3660         }
3661
3662         sid.bv_len = ptr - sid.bv_val;
3663         assert( sid.bv_len == STRLENOF( "000" ) );
3664
3665         mod.bv_val = ptr + 1;
3666         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3667
3668         assert( mod.bv_len == STRLENOF( "000000" ) );
3669
3670         ber_dupbv_x( normalized, val, ctx );
3671
3672         for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
3673                 i < normalized->bv_len; i++ )
3674         {
3675                 /* assume it's already validated that's all hex digits */
3676                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3677         }
3678
3679         return LDAP_SUCCESS;
3680 }
3681
3682 static int
3683 csnPretty(
3684         Syntax *syntax,
3685         struct berval *val,
3686         struct berval *out,
3687         void *ctx )
3688 {
3689         return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3690 }
3691
3692 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
3693 /* slight optimization - does not need the start parameter */
3694 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
3695 enum { start = 0 };
3696 #endif
3697
3698 static int
3699 check_time_syntax (struct berval *val,
3700         int start,
3701         int *parts,
3702         struct berval *fraction)
3703 {
3704         /*
3705          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
3706          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
3707          * GeneralizedTime supports leap seconds, UTCTime does not.
3708          */
3709         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
3710         static const int mdays[2][12] = {
3711                 /* non-leap years */
3712                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
3713                 /* leap years */
3714                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
3715         };
3716         char *p, *e;
3717         int part, c, c1, c2, tzoffset, leapyear = 0;
3718
3719         p = val->bv_val;
3720         e = p + val->bv_len;
3721
3722 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3723         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
3724 #endif
3725         for (part = start; part < 7 && p < e; part++) {
3726                 c1 = *p;
3727                 if (!ASCII_DIGIT(c1)) {
3728                         break;
3729                 }
3730                 p++;
3731                 if (p == e) {
3732                         return LDAP_INVALID_SYNTAX;
3733                 }
3734                 c = *p++;
3735                 if (!ASCII_DIGIT(c)) {
3736                         return LDAP_INVALID_SYNTAX;
3737                 }
3738                 c += c1 * 10 - '0' * 11;
3739                 if ((part | 1) == 3) {
3740                         --c;
3741                         if (c < 0) {
3742                                 return LDAP_INVALID_SYNTAX;
3743                         }
3744                 }
3745                 if (c >= ceiling[part]) {
3746                         if (! (c == 60 && part == 6 && start == 0))
3747                                 return LDAP_INVALID_SYNTAX;
3748                 }
3749                 parts[part] = c;
3750         }
3751         if (part < 5 + start) {
3752                 return LDAP_INVALID_SYNTAX;
3753         }
3754         for (; part < 9; part++) {
3755                 parts[part] = 0;
3756         }
3757
3758         /* leapyear check for the Gregorian calendar (year>1581) */
3759         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
3760                 leapyear = 1;
3761         }
3762
3763         if (parts[3] >= mdays[leapyear][parts[2]]) {
3764                 return LDAP_INVALID_SYNTAX;
3765         }
3766
3767         if (start == 0) {
3768                 fraction->bv_val = p;
3769                 fraction->bv_len = 0;
3770                 if (p < e && (*p == '.' || *p == ',')) {
3771                         char *end_num;
3772                         while (++p < e && ASCII_DIGIT(*p)) {
3773                                 /* EMTPY */;
3774                         }
3775                         if (p - fraction->bv_val == 1) {
3776                                 return LDAP_INVALID_SYNTAX;
3777                         }
3778                         for (end_num = p; end_num[-1] == '0'; --end_num) {
3779                                 /* EMPTY */;
3780                         }
3781                         c = end_num - fraction->bv_val;
3782                         if (c != 1) fraction->bv_len = c;
3783                 }
3784         }
3785
3786         if (p == e) {
3787                 /* no time zone */
3788                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3789         }
3790
3791         tzoffset = *p++;
3792         switch (tzoffset) {
3793         default:
3794                 return LDAP_INVALID_SYNTAX;
3795         case 'Z':
3796                 /* UTC */
3797                 break;
3798         case '+':
3799         case '-':
3800                 for (part = 7; part < 9 && p < e; part++) {
3801                         c1 = *p;
3802                         if (!ASCII_DIGIT(c1)) {
3803                                 break;
3804                         }
3805                         p++;
3806                         if (p == e) {
3807                                 return LDAP_INVALID_SYNTAX;
3808                         }
3809                         c2 = *p++;
3810                         if (!ASCII_DIGIT(c2)) {
3811                                 return LDAP_INVALID_SYNTAX;
3812                         }
3813                         parts[part] = c1 * 10 + c2 - '0' * 11;
3814                         if (parts[part] >= ceiling[part]) {
3815                                 return LDAP_INVALID_SYNTAX;
3816                         }
3817                 }
3818                 if (part < 8 + start) {
3819                         return LDAP_INVALID_SYNTAX;
3820                 }
3821
3822                 if (tzoffset == '-') {
3823                         /* negative offset to UTC, ie west of Greenwich */
3824                         parts[4] += parts[7];
3825                         parts[5] += parts[8];
3826                         /* offset is just hhmm, no seconds */
3827                         for (part = 6; --part >= 0; ) {
3828                                 if (part != 3) {
3829                                         c = ceiling[part];
3830                                 } else {
3831                                         c = mdays[leapyear][parts[2]];
3832                                 }
3833                                 if (parts[part] >= c) {
3834                                         if (part == 0) {
3835                                                 return LDAP_INVALID_SYNTAX;
3836                                         }
3837                                         parts[part] -= c;
3838                                         parts[part - 1]++;
3839                                         continue;
3840                                 } else if (part != 5) {
3841                                         break;
3842                                 }
3843                         }
3844                 } else {
3845                         /* positive offset to UTC, ie east of Greenwich */
3846                         parts[4] -= parts[7];
3847                         parts[5] -= parts[8];
3848                         for (part = 6; --part >= 0; ) {
3849                                 if (parts[part] < 0) {
3850                                         if (part == 0) {
3851                                                 return LDAP_INVALID_SYNTAX;
3852                                         }
3853                                         if (part != 3) {
3854                                                 c = ceiling[part];
3855                                         } else {
3856                                                 /* make first arg to % non-negative */
3857                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
3858                                         }
3859                                         parts[part] += c;
3860                                         parts[part - 1]--;
3861                                         continue;
3862                                 } else if (part != 5) {
3863                                         break;
3864                                 }
3865                         }
3866                 }
3867         }
3868
3869         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3870 }
3871
3872 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3873
3874 #if 0
3875 static int
3876 xutcTimeNormalize(
3877         Syntax *syntax,
3878         struct berval *val,
3879         struct berval *normalized )
3880 {
3881         int parts[9], rc;
3882
3883         rc = check_time_syntax(val, 1, parts, NULL);
3884         if (rc != LDAP_SUCCESS) {
3885                 return rc;
3886         }
3887
3888         normalized->bv_val = ch_malloc( 14 );
3889         if ( normalized->bv_val == NULL ) {
3890                 return LBER_ERROR_MEMORY;
3891         }
3892
3893         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
3894                 parts[1], parts[2] + 1, parts[3] + 1,
3895                 parts[4], parts[5], parts[6] );
3896         normalized->bv_len = 13;
3897
3898         return LDAP_SUCCESS;
3899 }
3900 #endif /* 0 */
3901
3902 static int
3903 utcTimeValidate(
3904         Syntax *syntax,
3905         struct berval *in )
3906 {
3907         int parts[9];
3908         return check_time_syntax(in, 1, parts, NULL);
3909 }
3910
3911 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
3912
3913 static int
3914 generalizedTimeValidate(
3915         Syntax *syntax,
3916         struct berval *in )
3917 {
3918         int parts[9];
3919         struct berval fraction;
3920         return check_time_syntax(in, 0, parts, &fraction);
3921 }
3922
3923 static int
3924 generalizedTimeNormalize(
3925         slap_mask_t usage,
3926         Syntax *syntax,
3927         MatchingRule *mr,
3928         struct berval *val,
3929         struct berval *normalized,
3930         void *ctx )
3931 {
3932         int parts[9], rc;
3933         unsigned int len;
3934         struct berval fraction;
3935
3936         rc = check_time_syntax(val, 0, parts, &fraction);
3937         if (rc != LDAP_SUCCESS) {
3938                 return rc;
3939         }
3940
3941         len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
3942         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
3943         if ( BER_BVISNULL( normalized ) ) {
3944                 return LBER_ERROR_MEMORY;
3945         }
3946
3947         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
3948                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
3949                 parts[4], parts[5], parts[6] );
3950         if ( !BER_BVISEMPTY( &fraction ) ) {
3951                 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
3952                         fraction.bv_val, fraction.bv_len );
3953                 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
3954         }
3955         strcpy( normalized->bv_val + len-1, "Z" );
3956         normalized->bv_len = len;
3957
3958         return LDAP_SUCCESS;
3959 }
3960
3961 static int
3962 generalizedTimeOrderingMatch(
3963         int *matchp,
3964         slap_mask_t flags,
3965         Syntax *syntax,
3966         MatchingRule *mr,
3967         struct berval *value,
3968         void *assertedValue )
3969 {
3970         struct berval *asserted = (struct berval *) assertedValue;
3971         ber_len_t v_len  = value->bv_len;
3972         ber_len_t av_len = asserted->bv_len;
3973
3974         /* ignore trailing 'Z' when comparing */
3975         int match = memcmp( value->bv_val, asserted->bv_val,
3976                 (v_len < av_len ? v_len : av_len) - 1 );
3977         if ( match == 0 ) match = v_len - av_len;
3978
3979         *matchp = match;
3980         return LDAP_SUCCESS;
3981 }
3982
3983 /* Index generation function */
3984 int generalizedTimeIndexer(
3985         slap_mask_t use,
3986         slap_mask_t flags,
3987         Syntax *syntax,
3988         MatchingRule *mr,
3989         struct berval *prefix,
3990         BerVarray values,
3991         BerVarray *keysp,
3992         void *ctx )
3993 {
3994         int i, j;
3995         BerVarray keys;
3996         char tmp[5];
3997         BerValue bvtmp; /* 40 bit index */
3998         struct lutil_tm tm;
3999         struct lutil_timet tt;
4000
4001         bvtmp.bv_len = sizeof(tmp);
4002         bvtmp.bv_val = tmp;
4003         for( i=0; values[i].bv_val != NULL; i++ ) {
4004                 /* just count them */
4005         }
4006
4007         /* we should have at least one value at this point */
4008         assert( i > 0 );
4009
4010         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
4011
4012         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4013         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
4014                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
4015                 /* Use 40 bits of time for key */
4016                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
4017                         lutil_tm2time( &tm, &tt );
4018                         tmp[0] = tt.tt_gsec & 0xff;
4019                         tmp[4] = tt.tt_sec & 0xff;
4020                         tt.tt_sec >>= 8;
4021                         tmp[3] = tt.tt_sec & 0xff;
4022                         tt.tt_sec >>= 8;
4023                         tmp[2] = tt.tt_sec & 0xff;
4024                         tt.tt_sec >>= 8;
4025                         tmp[1] = tt.tt_sec & 0xff;
4026                         
4027                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
4028                 }
4029         }
4030
4031         keys[j].bv_val = NULL;
4032         keys[j].bv_len = 0;
4033
4034         *keysp = keys;
4035
4036         return LDAP_SUCCESS;
4037 }
4038
4039 /* Index generation function */
4040 int generalizedTimeFilter(
4041         slap_mask_t use,
4042         slap_mask_t flags,
4043         Syntax *syntax,
4044         MatchingRule *mr,
4045         struct berval *prefix,
4046         void * assertedValue,
4047         BerVarray *keysp,
4048         void *ctx )
4049 {
4050         BerVarray keys;
4051         char tmp[5];
4052         BerValue bvtmp; /* 40 bit index */
4053         BerValue *value = (BerValue *) assertedValue;
4054         struct lutil_tm tm;
4055         struct lutil_timet tt;
4056         
4057         bvtmp.bv_len = sizeof(tmp);
4058         bvtmp.bv_val = tmp;
4059         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4060         /* Use 40 bits of time for key */
4061         if ( value->bv_val && value->bv_len >= 10 &&
4062                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
4063
4064                 lutil_tm2time( &tm, &tt );
4065                 tmp[0] = tt.tt_gsec & 0xff;
4066                 tmp[4] = tt.tt_sec & 0xff;
4067                 tt.tt_sec >>= 8;
4068                 tmp[3] = tt.tt_sec & 0xff;
4069                 tt.tt_sec >>= 8;
4070                 tmp[2] = tt.tt_sec & 0xff;
4071                 tt.tt_sec >>= 8;
4072                 tmp[1] = tt.tt_sec & 0xff;
4073
4074                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
4075                 ber_dupbv_x(keys, &bvtmp, ctx );
4076                 keys[1].bv_val = NULL;
4077                 keys[1].bv_len = 0;
4078         } else {
4079                 keys = NULL;
4080         }
4081
4082         *keysp = keys;
4083
4084         return LDAP_SUCCESS;
4085 }
4086
4087 static int
4088 deliveryMethodValidate(
4089         Syntax *syntax,
4090         struct berval *val )
4091 {
4092 #undef LENOF
4093 #define LENOF(s) (sizeof(s)-1)
4094         struct berval tmp = *val;
4095         /*
4096      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
4097          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
4098          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
4099          */
4100 again:
4101         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4102
4103         switch( tmp.bv_val[0] ) {
4104         case 'a':
4105         case 'A':
4106                 if(( tmp.bv_len >= LENOF("any") ) &&
4107                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
4108                 {
4109                         tmp.bv_len -= LENOF("any");
4110                         tmp.bv_val += LENOF("any");
4111                         break;
4112                 }
4113                 return LDAP_INVALID_SYNTAX;
4114
4115         case 'm':
4116         case 'M':
4117                 if(( tmp.bv_len >= LENOF("mhs") ) &&
4118                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
4119                 {
4120                         tmp.bv_len -= LENOF("mhs");
4121                         tmp.bv_val += LENOF("mhs");
4122                         break;
4123                 }
4124                 return LDAP_INVALID_SYNTAX;
4125
4126         case 'p':
4127         case 'P':
4128                 if(( tmp.bv_len >= LENOF("physical") ) &&
4129                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
4130                 {
4131                         tmp.bv_len -= LENOF("physical");
4132                         tmp.bv_val += LENOF("physical");
4133                         break;
4134                 }
4135                 return LDAP_INVALID_SYNTAX;
4136
4137         case 't':
4138         case 'T': /* telex or teletex or telephone */
4139                 if(( tmp.bv_len >= LENOF("telex") ) &&
4140                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
4141                 {
4142                         tmp.bv_len -= LENOF("telex");
4143                         tmp.bv_val += LENOF("telex");
4144                         break;
4145                 }
4146                 if(( tmp.bv_len >= LENOF("teletex") ) &&
4147                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
4148                 {
4149                         tmp.bv_len -= LENOF("teletex");
4150                         tmp.bv_val += LENOF("teletex");
4151                         break;
4152                 }
4153                 if(( tmp.bv_len >= LENOF("telephone") ) &&
4154                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
4155                 {
4156                         tmp.bv_len -= LENOF("telephone");
4157                         tmp.bv_val += LENOF("telephone");
4158                         break;
4159                 }
4160                 return LDAP_INVALID_SYNTAX;
4161
4162         case 'g':
4163         case 'G': /* g3fax or g4fax */
4164                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
4165                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
4166                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
4167                 {
4168                         tmp.bv_len -= LENOF("g3fax");
4169                         tmp.bv_val += LENOF("g3fax");
4170                         break;
4171                 }
4172                 return LDAP_INVALID_SYNTAX;
4173
4174         case 'i':
4175         case 'I':
4176                 if(( tmp.bv_len >= LENOF("ia5") ) &&
4177                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
4178                 {
4179                         tmp.bv_len -= LENOF("ia5");
4180                         tmp.bv_val += LENOF("ia5");
4181                         break;
4182                 }
4183                 return LDAP_INVALID_SYNTAX;
4184
4185         case 'v':
4186         case 'V':
4187                 if(( tmp.bv_len >= LENOF("videotex") ) &&
4188                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
4189                 {
4190                         tmp.bv_len -= LENOF("videotex");
4191                         tmp.bv_val += LENOF("videotex");
4192                         break;
4193                 }
4194                 return LDAP_INVALID_SYNTAX;
4195
4196         default:
4197                 return LDAP_INVALID_SYNTAX;
4198         }
4199
4200         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
4201
4202         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4203                 tmp.bv_len++;
4204                 tmp.bv_val--;
4205         }
4206         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
4207                 tmp.bv_len++;
4208                 tmp.bv_val--;
4209         } else {
4210                 return LDAP_INVALID_SYNTAX;
4211         }
4212         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4213                 tmp.bv_len++;
4214                 tmp.bv_val--;
4215         }
4216
4217         goto again;
4218 }
4219
4220 static int
4221 nisNetgroupTripleValidate(
4222         Syntax *syntax,
4223         struct berval *val )
4224 {
4225         char *p, *e;
4226         int commas = 0;
4227
4228         if ( BER_BVISEMPTY( val ) ) {
4229                 return LDAP_INVALID_SYNTAX;
4230         }
4231
4232         p = (char *)val->bv_val;
4233         e = p + val->bv_len;
4234
4235         if ( *p != '(' /*')'*/ ) {
4236                 return LDAP_INVALID_SYNTAX;
4237         }
4238
4239         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
4240                 if ( *p == ',' ) {
4241                         commas++;
4242                         if ( commas > 2 ) {
4243                                 return LDAP_INVALID_SYNTAX;
4244                         }
4245
4246                 } else if ( !AD_CHAR( *p ) ) {
4247                         return LDAP_INVALID_SYNTAX;
4248                 }
4249         }
4250
4251         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
4252                 return LDAP_INVALID_SYNTAX;
4253         }
4254
4255         p++;
4256
4257         if (p != e) {
4258                 return LDAP_INVALID_SYNTAX;
4259         }
4260
4261         return LDAP_SUCCESS;
4262 }
4263
4264 static int
4265 bootParameterValidate(
4266         Syntax *syntax,
4267         struct berval *val )
4268 {
4269         char *p, *e;
4270
4271         if ( BER_BVISEMPTY( val ) ) {
4272                 return LDAP_INVALID_SYNTAX;
4273         }
4274
4275         p = (char *)val->bv_val;
4276         e = p + val->bv_len;
4277
4278         /* key */
4279         for (; ( p < e ) && ( *p != '=' ); p++ ) {
4280                 if ( !AD_CHAR( *p ) ) {
4281                         return LDAP_INVALID_SYNTAX;
4282                 }
4283         }
4284
4285         if ( *p != '=' ) {
4286                 return LDAP_INVALID_SYNTAX;
4287         }
4288
4289         /* server */
4290         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
4291                 if ( !AD_CHAR( *p ) ) {
4292                         return LDAP_INVALID_SYNTAX;
4293                 }
4294         }
4295
4296         if ( *p != ':' ) {
4297                 return LDAP_INVALID_SYNTAX;
4298         }
4299
4300         /* path */
4301         for ( p++; p < e; p++ ) {
4302                 if ( !SLAP_PRINTABLE( *p ) ) {
4303                         return LDAP_INVALID_SYNTAX;
4304                 }
4305         }
4306
4307         return LDAP_SUCCESS;
4308 }
4309
4310 static int
4311 firstComponentNormalize(
4312         slap_mask_t usage,
4313         Syntax *syntax,
4314         MatchingRule *mr,
4315         struct berval *val,
4316         struct berval *normalized,
4317         void *ctx )
4318 {
4319         int rc;
4320         struct berval comp;
4321         ber_len_t len;
4322
4323         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
4324                 ber_dupbv_x( normalized, val, ctx );
4325                 return LDAP_SUCCESS;
4326         }
4327
4328         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4329
4330         if( val->bv_val[0] != '(' /*')'*/ &&
4331                 val->bv_val[0] != '{' /*'}'*/ )
4332         {
4333                 return LDAP_INVALID_SYNTAX;
4334         }
4335
4336         /* trim leading white space */
4337         for( len=1;
4338                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
4339                 len++ )
4340         {
4341                 /* empty */
4342         }
4343
4344         /* grab next word */
4345         comp.bv_val = &val->bv_val[len];
4346         len = val->bv_len - len;
4347         for( comp.bv_len = 0;
4348                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
4349                 comp.bv_len++ )
4350         {
4351                 /* empty */
4352         }
4353
4354         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
4355                 rc = numericoidValidate( NULL, &comp );
4356         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
4357                 rc = integerValidate( NULL, &comp );
4358         } else {
4359                 rc = LDAP_INVALID_SYNTAX;
4360         }
4361         
4362
4363         if( rc == LDAP_SUCCESS ) {
4364                 ber_dupbv_x( normalized, &comp, ctx );
4365         }
4366
4367         return rc;
4368 }
4369
4370 static char *country_gen_syn[] = {
4371         "1.3.6.1.4.1.1466.115.121.1.15",
4372         "1.3.6.1.4.1.1466.115.121.1.26",
4373         "1.3.6.1.4.1.1466.115.121.1.44",
4374         NULL
4375 };
4376
4377 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
4378 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
4379
4380 static slap_syntax_defs_rec syntax_defs[] = {
4381         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
4382                 X_BINARY X_NOT_H_R ")",
4383                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
4384         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
4385                 0, NULL, NULL, NULL},
4386         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
4387                 0, NULL, NULL, NULL},
4388         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
4389                 X_NOT_H_R ")",
4390                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4391         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
4392                 X_NOT_H_R ")",
4393                 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4394         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
4395                 0, NULL, bitStringValidate, NULL },
4396         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
4397                 0, NULL, booleanValidate, NULL},
4398         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
4399                 X_BINARY X_NOT_H_R ")",
4400                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4401                 NULL, certificateValidate, NULL},
4402         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
4403                 X_BINARY X_NOT_H_R ")",
4404                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4405                 NULL, certificateListValidate, NULL},
4406         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4407                 X_BINARY X_NOT_H_R ")",
4408                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4409                 NULL, sequenceValidate, NULL},
4410 #if 0   /* need to go __after__ printableString */
4411         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4412                 0, "1.3.6.1.4.1.1466.115.121.1.44",
4413                 countryStringValidate, NULL},
4414 #endif
4415         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4416                 0, NULL, dnValidate, dnPretty},
4417         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
4418                 0, NULL, rdnValidate, rdnPretty},
4419 #ifdef LDAP_COMP_MATCH
4420         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
4421                 0, NULL, allComponentsValidate, NULL},
4422         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
4423                 0, NULL, componentFilterValidate, NULL},
4424 #endif
4425         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4426                 0, NULL, NULL, NULL},
4427         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4428                 0, NULL, deliveryMethodValidate, NULL},
4429         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4430                 0, NULL, UTF8StringValidate, NULL},
4431         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4432                 0, NULL, NULL, NULL},
4433         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4434                 0, NULL, NULL, NULL},
4435         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4436                 0, NULL, NULL, NULL},
4437         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4438                 0, NULL, NULL, NULL},
4439         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4440                 0, NULL, NULL, NULL},
4441         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4442                 0, NULL, printablesStringValidate, NULL},
4443         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4444                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
4445         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4446                 0, NULL, generalizedTimeValidate, NULL},
4447         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4448                 0, NULL, NULL, NULL},
4449         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4450                 0, NULL, IA5StringValidate, NULL},
4451         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4452                 0, NULL, integerValidate, NULL},
4453         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4454                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4455         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4456                 0, NULL, NULL, NULL},
4457         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4458                 0, NULL, NULL, NULL},
4459         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4460                 0, NULL, NULL, NULL},
4461         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4462                 0, NULL, NULL, NULL},
4463         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4464                 0, NULL, NULL, NULL},
4465         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4466                 0, NULL, nameUIDValidate, nameUIDPretty },
4467         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4468                 0, NULL, NULL, NULL},
4469         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4470                 0, NULL, numericStringValidate, NULL},
4471         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4472                 0, NULL, NULL, NULL},
4473         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4474                 0, NULL, numericoidValidate, NULL},
4475         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4476                 0, NULL, IA5StringValidate, NULL},
4477         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4478                 0, NULL, blobValidate, NULL},
4479         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4480                 0, NULL, UTF8StringValidate, NULL},
4481         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4482                 0, NULL, NULL, NULL},
4483         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4484                 0, NULL, NULL, NULL},
4485         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4486                 0, NULL, printableStringValidate, NULL},
4487         /* moved here because now depends on Directory String, IA5 String 
4488          * and Printable String */
4489         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4490                 0, country_gen_syn, countryStringValidate, NULL},
4491         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
4492 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
4493                 0, NULL, subtreeSpecificationValidate, NULL},
4494         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4495                 X_BINARY X_NOT_H_R ")",
4496                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4497         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4498                 0, NULL, printableStringValidate, NULL},
4499         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4500                 0, NULL, NULL, NULL},
4501         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4502                 0, NULL, printablesStringValidate, NULL},
4503 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4504         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4505                 0, NULL, utcTimeValidate, NULL},
4506 #endif
4507         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4508                 0, NULL, NULL, NULL},
4509         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4510                 0, NULL, NULL, NULL},
4511         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4512                 0, NULL, NULL, NULL},
4513         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4514                 0, NULL, NULL, NULL},
4515         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4516                 0, NULL, NULL, NULL},
4517
4518         /* RFC 2307 NIS Syntaxes */
4519         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
4520                 0, NULL, nisNetgroupTripleValidate, NULL},
4521         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
4522                 0, NULL, bootParameterValidate, NULL},
4523
4524         /* draft-zeilenga-ldap-x509 */
4525         {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
4526                 SLAP_SYNTAX_HIDE, NULL,
4527                 serialNumberAndIssuerValidate,
4528                 serialNumberAndIssuerPretty},
4529         {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
4530                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4531         {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
4532                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4533         {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
4534                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4535         {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
4536                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4537         {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
4538                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4539         {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
4540                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4541
4542 #ifdef SLAPD_AUTHPASSWD
4543         /* needs updating */
4544         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4545                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4546 #endif
4547
4548         {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
4549                 0, NULL, UUIDValidate, UUIDPretty},
4550
4551         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
4552                 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
4553
4554         {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
4555                 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
4556
4557         /* OpenLDAP Void Syntax */
4558         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4559                 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
4560
4561         /* FIXME: OID is unused, but not registered yet */
4562         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
4563                 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
4564
4565         {NULL, 0, NULL, NULL, NULL}
4566 };
4567
4568 char *csnSIDMatchSyntaxes[] = {
4569         "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
4570         NULL
4571 };
4572 char *certificateExactMatchSyntaxes[] = {
4573         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4574         NULL
4575 };
4576 #ifdef LDAP_COMP_MATCH
4577 char *componentFilterMatchSyntaxes[] = {
4578         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4579         NULL
4580 };
4581 #endif
4582 char *directoryStringSyntaxes[] = {
4583         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
4584         NULL
4585 };
4586 char *integerFirstComponentMatchSyntaxes[] = {
4587         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
4588         "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
4589         NULL
4590 };
4591 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
4592         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
4593         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
4594         "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
4595         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
4596         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
4597         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
4598         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
4599         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
4600         NULL
4601 };
4602
4603 /*
4604  * Other matching rules in X.520 that we do not use (yet):
4605  *
4606  * 2.5.13.25    uTCTimeMatch
4607  * 2.5.13.26    uTCTimeOrderingMatch
4608  * 2.5.13.31*   directoryStringFirstComponentMatch
4609  * 2.5.13.32*   wordMatch
4610  * 2.5.13.33*   keywordMatch
4611  * 2.5.13.36+   certificatePairExactMatch
4612  * 2.5.13.37+   certificatePairMatch
4613  * 2.5.13.38+   certificateListExactMatch
4614  * 2.5.13.39+   certificateListMatch
4615  * 2.5.13.40+   algorithmIdentifierMatch
4616  * 2.5.13.41*   storedPrefixMatch
4617  * 2.5.13.42    attributeCertificateMatch
4618  * 2.5.13.43    readerAndKeyIDMatch
4619  * 2.5.13.44    attributeIntegrityMatch
4620  *
4621  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
4622  * (+) described in draft-zeilenga-ldap-x509
4623  */
4624 static slap_mrule_defs_rec mrule_defs[] = {
4625         /*
4626          * EQUALITY matching rules must be listed after associated APPROX
4627          * matching rules.  So, we list all APPROX matching rules first.
4628          */
4629         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4630                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4631                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4632                 NULL, NULL, directoryStringApproxMatch,
4633                 directoryStringApproxIndexer, directoryStringApproxFilter,
4634                 NULL},
4635
4636         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4637                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4638                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4639                 NULL, NULL, IA5StringApproxMatch,
4640                 IA5StringApproxIndexer, IA5StringApproxFilter,
4641                 NULL},
4642
4643         /*
4644          * Other matching rules
4645          */
4646         
4647         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4648                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4649                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4650                 NULL, NULL, octetStringMatch,
4651                 octetStringIndexer, octetStringFilter,
4652                 NULL },
4653
4654         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4655                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4656                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4657                 NULL, dnNormalize, dnMatch,
4658                 octetStringIndexer, octetStringFilter,
4659                 NULL },
4660
4661         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
4662                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4663                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4664                 NULL, dnNormalize, dnRelativeMatch,
4665                 NULL, NULL,
4666                 NULL },
4667
4668         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
4669                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4670                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4671                 NULL, dnNormalize, dnRelativeMatch,
4672                 NULL, NULL,
4673                 NULL },
4674
4675         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
4676                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4677                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4678                 NULL, dnNormalize, dnRelativeMatch,
4679                 NULL, NULL,
4680                 NULL },
4681
4682         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
4683                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4684                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4685                 NULL, dnNormalize, dnRelativeMatch,
4686                 NULL, NULL,
4687                 NULL },
4688
4689         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
4690                 "SYNTAX 1.2.36.79672281.1.5.0 )",
4691                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4692                 NULL, rdnNormalize, rdnMatch,
4693                 octetStringIndexer, octetStringFilter,
4694                 NULL },
4695
4696 #ifdef LDAP_COMP_MATCH
4697         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
4698                 "SYNTAX 1.2.36.79672281.1.5.2 )",
4699                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
4700                 NULL, NULL , componentFilterMatch,
4701                 octetStringIndexer, octetStringFilter,
4702                 NULL },
4703
4704         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
4705                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4706                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4707                 NULL, NULL , allComponentsMatch,
4708                 octetStringIndexer, octetStringFilter,
4709                 NULL },
4710
4711         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
4712                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4713                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4714                 NULL, NULL , directoryComponentsMatch,
4715                 octetStringIndexer, octetStringFilter,
4716                 NULL },
4717 #endif
4718
4719         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4720                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4721                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4722                 NULL, UTF8StringNormalize, octetStringMatch,
4723                 octetStringIndexer, octetStringFilter,
4724                 directoryStringApproxMatchOID },
4725
4726         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4727                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4728                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4729                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4730                 NULL, NULL,
4731                 "caseIgnoreMatch" },
4732
4733         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4734                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4735                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4736                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4737                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4738                 "caseIgnoreMatch" },
4739
4740         {"( 2.5.13.5 NAME 'caseExactMatch' "
4741                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4742                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4743                 NULL, UTF8StringNormalize, octetStringMatch,
4744                 octetStringIndexer, octetStringFilter,
4745                 directoryStringApproxMatchOID },
4746
4747         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4748                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4749                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4750                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4751                 NULL, NULL,
4752                 "caseExactMatch" },
4753
4754         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4755                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4756                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4757                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4758                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4759                 "caseExactMatch" },
4760
4761         {"( 2.5.13.8 NAME 'numericStringMatch' "
4762                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4763                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4764                 NULL, numericStringNormalize, octetStringMatch,
4765                 octetStringIndexer, octetStringFilter,
4766                 NULL },
4767
4768         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
4769                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4770                 SLAP_MR_ORDERING, NULL,
4771                 NULL, numericStringNormalize, octetStringOrderingMatch,
4772                 NULL, NULL,
4773                 "numericStringMatch" },
4774
4775         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4776                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4777                 SLAP_MR_SUBSTR, NULL,
4778                 NULL, numericStringNormalize, octetStringSubstringsMatch,
4779                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4780                 "numericStringMatch" },
4781
4782         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4783                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4784                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4785                 NULL, NULL, NULL, NULL, NULL, NULL },
4786
4787         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4788                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4789                 SLAP_MR_SUBSTR, NULL,
4790                 NULL, NULL, NULL, NULL, NULL,
4791                 "caseIgnoreListMatch" },
4792
4793         {"( 2.5.13.13 NAME 'booleanMatch' "
4794                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
4795                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4796                 NULL, NULL, booleanMatch,
4797                 octetStringIndexer, octetStringFilter,
4798                 NULL },
4799
4800         {"( 2.5.13.14 NAME 'integerMatch' "
4801                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4802                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4803                 NULL, NULL, integerMatch,
4804                 integerIndexer, integerFilter,
4805                 NULL },
4806
4807         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
4808                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4809                 SLAP_MR_ORDERING, NULL,
4810                 NULL, NULL, integerMatch,
4811                 NULL, NULL,
4812                 "integerMatch" },
4813
4814         {"( 2.5.13.16 NAME 'bitStringMatch' "
4815                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
4816                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4817                 NULL, NULL, octetStringMatch,
4818                 octetStringIndexer, octetStringFilter,
4819                 NULL },
4820
4821         {"( 2.5.13.17 NAME 'octetStringMatch' "
4822                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4823                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4824                 NULL, NULL, octetStringMatch,
4825                 octetStringIndexer, octetStringFilter,
4826                 NULL },
4827
4828         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
4829                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4830                 SLAP_MR_ORDERING, NULL,
4831                 NULL, NULL, octetStringOrderingMatch,
4832                 NULL, NULL,
4833                 "octetStringMatch" },
4834
4835         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
4836                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4837                 SLAP_MR_SUBSTR, NULL,
4838                 NULL, NULL, octetStringSubstringsMatch,
4839                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4840                 "octetStringMatch" },
4841
4842         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
4843                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
4844                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4845                 NULL,
4846                 telephoneNumberNormalize, octetStringMatch,
4847                 octetStringIndexer, octetStringFilter,
4848                 NULL },
4849
4850         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
4851                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4852                 SLAP_MR_SUBSTR, NULL,
4853                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
4854                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4855                 "telephoneNumberMatch" },
4856
4857         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
4858                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
4859                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4860                 NULL, NULL, NULL, NULL, NULL, NULL },
4861
4862         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
4863                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
4864                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4865                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
4866                 uniqueMemberIndexer, uniqueMemberFilter,
4867                 NULL },
4868
4869         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
4870                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
4871                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4872                 NULL, NULL, NULL, NULL, NULL, NULL },
4873
4874         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
4875                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4876                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
4877                 NULL, generalizedTimeNormalize, octetStringMatch,
4878                 generalizedTimeIndexer, generalizedTimeFilter,
4879                 NULL },
4880
4881         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
4882                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4883                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
4884                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
4885                 NULL, NULL,
4886                 "generalizedTimeMatch" },
4887
4888         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
4889                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4890                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4891                         integerFirstComponentMatchSyntaxes,
4892                 NULL, firstComponentNormalize, integerMatch,
4893                 octetStringIndexer, octetStringFilter,
4894                 NULL },
4895
4896         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
4897                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4898                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4899                         objectIdentifierFirstComponentMatchSyntaxes,
4900                 NULL, firstComponentNormalize, octetStringMatch,
4901                 octetStringIndexer, octetStringFilter,
4902                 NULL },
4903
4904         {"( 2.5.13.34 NAME 'certificateExactMatch' "
4905                 "SYNTAX 1.3.6.1.1.15.1 )",
4906                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
4907                 NULL, certificateExactNormalize, octetStringMatch,
4908                 octetStringIndexer, octetStringFilter,
4909                 NULL },
4910
4911         {"( 2.5.13.35 NAME 'certificateMatch' "
4912                 "SYNTAX 1.3.6.1.1.15.2 )",
4913                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4914                 NULL, NULL, NULL, NULL, NULL,
4915                 NULL },
4916
4917         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
4918                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4919                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4920                 NULL, IA5StringNormalize, octetStringMatch,
4921                 octetStringIndexer, octetStringFilter,
4922                 IA5StringApproxMatchOID },
4923
4924         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
4925                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4926                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4927                 NULL, IA5StringNormalize, octetStringMatch,
4928                 octetStringIndexer, octetStringFilter,
4929                 IA5StringApproxMatchOID },
4930
4931         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
4932                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4933                 SLAP_MR_SUBSTR, NULL,
4934                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
4935                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4936                 "caseIgnoreIA5Match" },
4937
4938         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
4939                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4940                 SLAP_MR_SUBSTR, NULL,
4941                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
4942                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4943                 "caseExactIA5Match" },
4944
4945 #ifdef SLAPD_AUTHPASSWD
4946         /* needs updating */
4947         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
4948                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4949                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
4950                 NULL, NULL, authPasswordMatch,
4951                 NULL, NULL,
4952                 NULL},
4953 #endif
4954
4955         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
4956                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4957                 SLAP_MR_EXT, NULL,
4958                 NULL, NULL, integerBitAndMatch,
4959                 NULL, NULL,
4960                 "integerMatch" },
4961
4962         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
4963                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4964                 SLAP_MR_EXT, NULL,
4965                 NULL, NULL, integerBitOrMatch,
4966                 NULL, NULL,
4967                 "integerMatch" },
4968
4969         {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
4970                 "SYNTAX 1.3.6.1.1.16.1 )",
4971                 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
4972                 NULL, UUIDNormalize, octetStringMatch,
4973                 octetStringIndexer, octetStringFilter,
4974                 NULL},
4975
4976         {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
4977                 "SYNTAX 1.3.6.1.1.16.1 )",
4978                 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
4979                 NULL, UUIDNormalize, octetStringOrderingMatch,
4980                 octetStringIndexer, octetStringFilter,
4981                 "UUIDMatch"},
4982
4983         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
4984                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
4985                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
4986                 NULL, csnNormalize, csnMatch,
4987                 csnIndexer, csnFilter,
4988                 NULL},
4989
4990         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
4991                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
4992                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
4993                 NULL, NULL, csnOrderingMatch,
4994                 NULL, NULL,
4995                 "CSNMatch" },
4996
4997         {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
4998                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
4999                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
5000                 NULL, csnSidNormalize, octetStringMatch,
5001                 octetStringIndexer, octetStringFilter,
5002                 NULL },
5003
5004         /* FIXME: OID is unused, but not registered yet */
5005         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
5006                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
5007                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5008                 NULL, authzNormalize, authzMatch,
5009                 NULL, NULL,
5010                 NULL},
5011
5012         {NULL, SLAP_MR_NONE, NULL,
5013                 NULL, NULL, NULL, NULL, NULL,
5014                 NULL }
5015 };
5016
5017 int
5018 slap_schema_init( void )
5019 {
5020         int             res;
5021         int             i;
5022
5023         /* we should only be called once (from main) */
5024         assert( schema_init_done == 0 );
5025
5026         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
5027                 res = register_syntax( &syntax_defs[i] );
5028
5029                 if ( res ) {
5030                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
5031                                  syntax_defs[i].sd_desc );
5032                         return LDAP_OTHER;
5033                 }
5034         }
5035
5036         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
5037                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
5038                         mrule_defs[i].mrd_compat_syntaxes == NULL )
5039                 {
5040                         fprintf( stderr,
5041                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
5042                                  mrule_defs[i].mrd_desc );
5043                         continue;
5044                 }
5045
5046                 res = register_matching_rule( &mrule_defs[i] );
5047
5048                 if ( res ) {
5049                         fprintf( stderr,
5050                                 "slap_schema_init: Error registering matching rule %s\n",
5051                                  mrule_defs[i].mrd_desc );
5052                         return LDAP_OTHER;
5053                 }
5054         }
5055
5056         res = slap_schema_load();
5057         schema_init_done = 1;
5058         return res;
5059 }
5060
5061 void
5062 schema_destroy( void )
5063 {
5064         oidm_destroy();
5065         oc_destroy();
5066         at_destroy();
5067         mr_destroy();
5068         mru_destroy();
5069         syn_destroy();
5070
5071         if( schema_init_done ) {
5072                 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
5073                 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
5074         }
5075 }