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