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