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