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