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