]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
ITS#5129 disallow Quick mode if DB_CONFIG has changed
[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.  They must be non-empty.
1449
1450 IA5String
1451   Basically same as PrintableString.  There are no examples in X.500,
1452   but same logic applies.  Empty strings are allowed.
1453
1454 -------------------------------------------------------------------*/
1455
1456 static int
1457 UTF8StringValidate(
1458         Syntax *syntax,
1459         struct berval *in )
1460 {
1461         ber_len_t count;
1462         int len;
1463         unsigned char *u = (unsigned char *)in->bv_val;
1464
1465         if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1466                 /* directory strings cannot be empty */
1467                 return LDAP_INVALID_SYNTAX;
1468         }
1469
1470         for( count = in->bv_len; count > 0; count -= len, u += len ) {
1471                 /* get the length indicated by the first byte */
1472                 len = LDAP_UTF8_CHARLEN2( u, len );
1473
1474                 /* very basic checks */
1475                 switch( len ) {
1476                         case 6:
1477                                 if( (u[5] & 0xC0) != 0x80 ) {
1478                                         return LDAP_INVALID_SYNTAX;
1479                                 }
1480                         case 5:
1481                                 if( (u[4] & 0xC0) != 0x80 ) {
1482                                         return LDAP_INVALID_SYNTAX;
1483                                 }
1484                         case 4:
1485                                 if( (u[3] & 0xC0) != 0x80 ) {
1486                                         return LDAP_INVALID_SYNTAX;
1487                                 }
1488                         case 3:
1489                                 if( (u[2] & 0xC0 )!= 0x80 ) {
1490                                         return LDAP_INVALID_SYNTAX;
1491                                 }
1492                         case 2:
1493                                 if( (u[1] & 0xC0) != 0x80 ) {
1494                                         return LDAP_INVALID_SYNTAX;
1495                                 }
1496                         case 1:
1497                                 /* CHARLEN already validated it */
1498                                 break;
1499                         default:
1500                                 return LDAP_INVALID_SYNTAX;
1501                 }
1502
1503                 /* make sure len corresponds with the offset
1504                         to the next character */
1505                 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1506         }
1507
1508         if( count != 0 ) {
1509                 return LDAP_INVALID_SYNTAX;
1510         }
1511
1512         return LDAP_SUCCESS;
1513 }
1514
1515 static int
1516 UTF8StringNormalize(
1517         slap_mask_t use,
1518         Syntax *syntax,
1519         MatchingRule *mr,
1520         struct berval *val,
1521         struct berval *normalized,
1522         void *ctx )
1523 {
1524         struct berval tmp, nvalue;
1525         int flags;
1526         int i, wasspace;
1527
1528         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
1529
1530         if( BER_BVISNULL( val ) ) {
1531                 /* assume we're dealing with a syntax (e.g., UTF8String)
1532                  * which allows empty strings
1533                  */
1534                 BER_BVZERO( normalized );
1535                 return LDAP_SUCCESS;
1536         }
1537
1538         flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1539                 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1540         flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1541                 ? LDAP_UTF8_APPROX : 0;
1542
1543         val = UTF8bvnormalize( val, &tmp, flags, ctx );
1544         if( val == NULL ) {
1545                 return LDAP_OTHER;
1546         }
1547         
1548         /* collapse spaces (in place) */
1549         nvalue.bv_len = 0;
1550         nvalue.bv_val = tmp.bv_val;
1551
1552         /* trim leading spaces? */
1553         wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1554                 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1555
1556         for( i = 0; i < tmp.bv_len; i++) {
1557                 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1558                         if( wasspace++ == 0 ) {
1559                                 /* trim repeated spaces */
1560                                 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1561                         }
1562                 } else {
1563                         wasspace = 0;
1564                         nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1565                 }
1566         }
1567
1568         if( !BER_BVISEMPTY( &nvalue ) ) {
1569                 /* trim trailing space? */
1570                 if( wasspace && (
1571                         (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1572                         ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1573                 {
1574                         --nvalue.bv_len;
1575                 }
1576                 nvalue.bv_val[nvalue.bv_len] = '\0';
1577
1578         } else {
1579                 /* string of all spaces is treated as one space */
1580                 nvalue.bv_val[0] = ' ';
1581                 nvalue.bv_val[1] = '\0';
1582                 nvalue.bv_len = 1;
1583         }
1584
1585         *normalized = nvalue;
1586         return LDAP_SUCCESS;
1587 }
1588
1589 static int
1590 directoryStringSubstringsMatch(
1591         int *matchp,
1592         slap_mask_t flags,
1593         Syntax *syntax,
1594         MatchingRule *mr,
1595         struct berval *value,
1596         void *assertedValue )
1597 {
1598         int match = 0;
1599         SubstringsAssertion *sub = assertedValue;
1600         struct berval left = *value;
1601         int i;
1602         int priorspace=0;
1603
1604         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1605                 if ( sub->sa_initial.bv_len > left.bv_len ) {
1606                         /* not enough left */
1607                         match = 1;
1608                         goto done;
1609                 }
1610
1611                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1612                         sub->sa_initial.bv_len );
1613
1614                 if ( match != 0 ) {
1615                         goto done;
1616                 }
1617
1618                 left.bv_val += sub->sa_initial.bv_len;
1619                 left.bv_len -= sub->sa_initial.bv_len;
1620
1621                 priorspace = ASCII_SPACE(
1622                         sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1623         }
1624
1625         if ( sub->sa_any ) {
1626                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1627                         ber_len_t idx;
1628                         char *p;
1629
1630                         if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] ) 
1631                                 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1632                         { 
1633                                 /* allow next space to match */
1634                                 left.bv_val--;
1635                                 left.bv_len++;
1636                         }
1637                         priorspace=0;
1638
1639 retry:
1640                         if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1641                                 continue;
1642                         }
1643
1644                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1645                                 /* not enough left */
1646                                 match = 1;
1647                                 goto done;
1648                         }
1649
1650                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1651
1652                         if( p == NULL ) {
1653                                 match = 1;
1654                                 goto done;
1655                         }
1656
1657                         idx = p - left.bv_val;
1658
1659                         if ( idx >= left.bv_len ) {
1660                                 /* this shouldn't happen */
1661                                 return LDAP_OTHER;
1662                         }
1663
1664                         left.bv_val = p;
1665                         left.bv_len -= idx;
1666
1667                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1668                                 /* not enough left */
1669                                 match = 1;
1670                                 goto done;
1671                         }
1672
1673                         match = memcmp( left.bv_val,
1674                                 sub->sa_any[i].bv_val,
1675                                 sub->sa_any[i].bv_len );
1676
1677                         if ( match != 0 ) {
1678                                 left.bv_val++;
1679                                 left.bv_len--;
1680                                 goto retry;
1681                         }
1682
1683                         left.bv_val += sub->sa_any[i].bv_len;
1684                         left.bv_len -= sub->sa_any[i].bv_len;
1685
1686                         priorspace = ASCII_SPACE(
1687                                 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1688                 }
1689         }
1690
1691         if ( !BER_BVISNULL( &sub->sa_final ) ) {
1692                 if( priorspace && !BER_BVISEMPTY( &sub->sa_final ) 
1693                         && ASCII_SPACE( sub->sa_final.bv_val[0] ))
1694                 { 
1695                         /* allow next space to match */
1696                         left.bv_val--;
1697                         left.bv_len++;
1698                 }
1699
1700                 if ( sub->sa_final.bv_len > left.bv_len ) {
1701                         /* not enough left */
1702                         match = 1;
1703                         goto done;
1704                 }
1705
1706                 match = memcmp( sub->sa_final.bv_val,
1707                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1708                         sub->sa_final.bv_len );
1709
1710                 if ( match != 0 ) {
1711                         goto done;
1712                 }
1713         }
1714
1715 done:
1716         *matchp = match;
1717         return LDAP_SUCCESS;
1718 }
1719
1720 #if defined(SLAPD_APPROX_INITIALS)
1721 #       define SLAPD_APPROX_DELIMITER "._ "
1722 #       define SLAPD_APPROX_WORDLEN 2
1723 #else
1724 #       define SLAPD_APPROX_DELIMITER " "
1725 #       define SLAPD_APPROX_WORDLEN 1
1726 #endif
1727
1728 static int
1729 approxMatch(
1730         int *matchp,
1731         slap_mask_t flags,
1732         Syntax *syntax,
1733         MatchingRule *mr,
1734         struct berval *value,
1735         void *assertedValue )
1736 {
1737         struct berval *nval, *assertv;
1738         char *val, **values, **words, *c;
1739         int i, count, len, nextchunk=0, nextavail=0;
1740
1741         /* Yes, this is necessary */
1742         nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
1743         if( nval == NULL ) {
1744                 *matchp = 1;
1745                 return LDAP_SUCCESS;
1746         }
1747
1748         /* Yes, this is necessary */
1749         assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1750                 NULL, LDAP_UTF8_APPROX, NULL );
1751         if( assertv == NULL ) {
1752                 ber_bvfree( nval );
1753                 *matchp = 1;
1754                 return LDAP_SUCCESS;
1755         }
1756
1757         /* Isolate how many words there are */
1758         for ( c = nval->bv_val, count = 1; *c; c++ ) {
1759                 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1760                 if ( c == NULL ) break;
1761                 *c = '\0';
1762                 count++;
1763         }
1764
1765         /* Get a phonetic copy of each word */
1766         words = (char **)ch_malloc( count * sizeof(char *) );
1767         values = (char **)ch_malloc( count * sizeof(char *) );
1768         for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
1769                 words[i] = c;
1770                 values[i] = phonetic(c);
1771         }
1772
1773         /* Work through the asserted value's words, to see if at least some
1774            of the words are there, in the same order. */
1775         len = 0;
1776         while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1777                 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1778                 if( len == 0 ) {
1779                         nextchunk++;
1780                         continue;
1781                 }
1782 #if defined(SLAPD_APPROX_INITIALS)
1783                 else if( len == 1 ) {
1784                         /* Single letter words need to at least match one word's initial */
1785                         for( i=nextavail; i<count; i++ )
1786                                 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1787                                         nextavail=i+1;
1788                                         break;
1789                                 }
1790                 }
1791 #endif
1792                 else {
1793                         /* Isolate the next word in the asserted value and phonetic it */
1794                         assertv->bv_val[nextchunk+len] = '\0';
1795                         val = phonetic( assertv->bv_val + nextchunk );
1796
1797                         /* See if this phonetic chunk is in the remaining words of *value */
1798                         for( i=nextavail; i<count; i++ ){
1799                                 if( !strcmp( val, values[i] ) ){
1800                                         nextavail = i+1;
1801                                         break;
1802                                 }
1803                         }
1804                         ch_free( val );
1805                 }
1806
1807                 /* This chunk in the asserted value was NOT within the *value. */
1808                 if( i >= count ) {
1809                         nextavail=-1;
1810                         break;
1811                 }
1812
1813                 /* Go on to the next word in the asserted value */
1814                 nextchunk += len+1;
1815         }
1816
1817         /* If some of the words were seen, call it a match */
1818         if( nextavail > 0 ) {
1819                 *matchp = 0;
1820         }
1821         else {
1822                 *matchp = 1;
1823         }
1824
1825         /* Cleanup allocs */
1826         ber_bvfree( assertv );
1827         for( i=0; i<count; i++ ) {
1828                 ch_free( values[i] );
1829         }
1830         ch_free( values );
1831         ch_free( words );
1832         ber_bvfree( nval );
1833
1834         return LDAP_SUCCESS;
1835 }
1836
1837 static int 
1838 approxIndexer(
1839         slap_mask_t use,
1840         slap_mask_t flags,
1841         Syntax *syntax,
1842         MatchingRule *mr,
1843         struct berval *prefix,
1844         BerVarray values,
1845         BerVarray *keysp,
1846         void *ctx )
1847 {
1848         char *c;
1849         int i,j, len, wordcount, keycount=0;
1850         struct berval *newkeys;
1851         BerVarray keys=NULL;
1852
1853         for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
1854                 struct berval val = BER_BVNULL;
1855                 /* Yes, this is necessary */
1856                 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
1857                 assert( !BER_BVISNULL( &val ) );
1858
1859                 /* Isolate how many words there are. There will be a key for each */
1860                 for( wordcount = 0, c = val.bv_val; *c; c++) {
1861                         len = strcspn(c, SLAPD_APPROX_DELIMITER);
1862                         if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1863                         c+= len;
1864                         if (*c == '\0') break;
1865                         *c = '\0';
1866                 }
1867
1868                 /* Allocate/increase storage to account for new keys */
1869                 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
1870                         * sizeof(struct berval) );
1871                 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1872                 if( keys ) ch_free( keys );
1873                 keys = newkeys;
1874
1875                 /* Get a phonetic copy of each word */
1876                 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1877                         len = strlen( c );
1878                         if( len < SLAPD_APPROX_WORDLEN ) continue;
1879                         ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1880                         keycount++;
1881                         i++;
1882                 }
1883
1884                 ber_memfree( val.bv_val );
1885         }
1886         BER_BVZERO( &keys[keycount] );
1887         *keysp = keys;
1888
1889         return LDAP_SUCCESS;
1890 }
1891
1892 static int 
1893 approxFilter(
1894         slap_mask_t use,
1895         slap_mask_t flags,
1896         Syntax *syntax,
1897         MatchingRule *mr,
1898         struct berval *prefix,
1899         void * assertedValue,
1900         BerVarray *keysp,
1901         void *ctx )
1902 {
1903         char *c;
1904         int i, count, len;
1905         struct berval *val;
1906         BerVarray keys;
1907
1908         /* Yes, this is necessary */
1909         val = UTF8bvnormalize( ((struct berval *)assertedValue),
1910                 NULL, LDAP_UTF8_APPROX, NULL );
1911         if( val == NULL || BER_BVISNULL( val ) ) {
1912                 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1913                 BER_BVZERO( &keys[0] );
1914                 *keysp = keys;
1915                 ber_bvfree( val );
1916                 return LDAP_SUCCESS;
1917         }
1918
1919         /* Isolate how many words there are. There will be a key for each */
1920         for( count = 0,c = val->bv_val; *c; c++) {
1921                 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1922                 if( len >= SLAPD_APPROX_WORDLEN ) count++;
1923                 c+= len;
1924                 if (*c == '\0') break;
1925                 *c = '\0';
1926         }
1927
1928         /* Allocate storage for new keys */
1929         keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1930
1931         /* Get a phonetic copy of each word */
1932         for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1933                 len = strlen(c);
1934                 if( len < SLAPD_APPROX_WORDLEN ) continue;
1935                 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1936                 i++;
1937         }
1938
1939         ber_bvfree( val );
1940
1941         BER_BVZERO( &keys[count] );
1942         *keysp = keys;
1943
1944         return LDAP_SUCCESS;
1945 }
1946
1947 /* Remove all spaces and '-' characters */
1948 static int
1949 telephoneNumberNormalize(
1950         slap_mask_t usage,
1951         Syntax *syntax,
1952         MatchingRule *mr,
1953         struct berval *val,
1954         struct berval *normalized,
1955         void *ctx )
1956 {
1957         char *p, *q;
1958
1959         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1960
1961         /* validator should have refused an empty string */
1962         assert( !BER_BVISEMPTY( val ) );
1963
1964         q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
1965
1966         for( p = val->bv_val; *p; p++ ) {
1967                 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1968                         *q++ = *p;
1969                 }
1970         }
1971         *q = '\0';
1972
1973         normalized->bv_len = q - normalized->bv_val;
1974
1975         if( BER_BVISEMPTY( normalized ) ) {
1976                 slap_sl_free( normalized->bv_val, ctx );
1977                 BER_BVZERO( normalized );
1978                 return LDAP_INVALID_SYNTAX;
1979         }
1980
1981         return LDAP_SUCCESS;
1982 }
1983
1984 int
1985 numericoidValidate(
1986         Syntax *syntax,
1987         struct berval *in )
1988 {
1989         struct berval val = *in;
1990
1991         if( BER_BVISEMPTY( &val ) ) {
1992                 /* disallow empty strings */
1993                 return LDAP_INVALID_SYNTAX;
1994         }
1995
1996         while( OID_LEADCHAR( val.bv_val[0] ) ) {
1997                 if ( val.bv_len == 1 ) {
1998                         return LDAP_SUCCESS;
1999                 }
2000
2001                 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2002                         break;
2003                 }
2004
2005                 val.bv_val++;
2006                 val.bv_len--;
2007
2008                 while ( OID_LEADCHAR( val.bv_val[0] )) {
2009                         val.bv_val++;
2010                         val.bv_len--;
2011
2012                         if ( val.bv_len == 0 ) {
2013                                 return LDAP_SUCCESS;
2014                         }
2015                 }
2016
2017                 if( !OID_SEPARATOR( val.bv_val[0] )) {
2018                         break;
2019                 }
2020
2021                 val.bv_val++;
2022                 val.bv_len--;
2023         }
2024
2025         return LDAP_INVALID_SYNTAX;
2026 }
2027
2028 static int
2029 integerValidate(
2030         Syntax *syntax,
2031         struct berval *in )
2032 {
2033         ber_len_t i;
2034         struct berval val = *in;
2035
2036         if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2037
2038         if ( val.bv_val[0] == '-' ) {
2039                 val.bv_len--;
2040                 val.bv_val++;
2041
2042                 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2043                         return LDAP_INVALID_SYNTAX;
2044                 }
2045
2046                 if( val.bv_val[0] == '0' ) { /* "-0" */
2047                         return LDAP_INVALID_SYNTAX;
2048                 }
2049
2050         } else if ( val.bv_val[0] == '0' ) {
2051                 if( val.bv_len > 1 ) { /* "0<more>" */
2052                         return LDAP_INVALID_SYNTAX;
2053                 }
2054
2055                 return LDAP_SUCCESS;
2056         }
2057
2058         for( i=0; i < val.bv_len; i++ ) {
2059                 if( !ASCII_DIGIT(val.bv_val[i]) ) {
2060                         return LDAP_INVALID_SYNTAX;
2061                 }
2062         }
2063
2064         return LDAP_SUCCESS;
2065 }
2066
2067 static int
2068 integerMatch(
2069         int *matchp,
2070         slap_mask_t flags,
2071         Syntax *syntax,
2072         MatchingRule *mr,
2073         struct berval *value,
2074         void *assertedValue )
2075 {
2076         struct berval *asserted = (struct berval *) assertedValue;
2077         int vsign = 1, asign = 1;       /* default sign = '+' */
2078         struct berval v, a;
2079         int match;
2080
2081         v = *value;
2082         if( v.bv_val[0] == '-' ) {
2083                 vsign = -1;
2084                 v.bv_val++;
2085                 v.bv_len--;
2086         }
2087
2088         if( BER_BVISEMPTY( &v ) ) vsign = 0;
2089
2090         a = *asserted;
2091         if( a.bv_val[0] == '-' ) {
2092                 asign = -1;
2093                 a.bv_val++;
2094                 a.bv_len--;
2095         }
2096
2097         if( BER_BVISEMPTY( &a ) ) vsign = 0;
2098
2099         match = vsign - asign;
2100         if( match == 0 ) {
2101                 match = ( v.bv_len != a.bv_len
2102                         ? ( v.bv_len < a.bv_len ? -1 : 1 )
2103                         : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2104                 if( vsign < 0 ) match = -match;
2105         }
2106
2107         *matchp = match;
2108         return LDAP_SUCCESS;
2109 }
2110         
2111 static int
2112 countryStringValidate(
2113         Syntax *syntax,
2114         struct berval *val )
2115 {
2116         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2117
2118         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2119                 return LDAP_INVALID_SYNTAX;
2120         }
2121         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2122                 return LDAP_INVALID_SYNTAX;
2123         }
2124
2125         return LDAP_SUCCESS;
2126 }
2127
2128 static int
2129 printableStringValidate(
2130         Syntax *syntax,
2131         struct berval *val )
2132 {
2133         ber_len_t i;
2134
2135         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2136
2137         for(i=0; i < val->bv_len; i++) {
2138                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2139                         return LDAP_INVALID_SYNTAX;
2140                 }
2141         }
2142
2143         return LDAP_SUCCESS;
2144 }
2145
2146 static int
2147 printablesStringValidate(
2148         Syntax *syntax,
2149         struct berval *val )
2150 {
2151         ber_len_t i, len;
2152
2153         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2154
2155         for(i=0,len=0; i < val->bv_len; i++) {
2156                 int c = val->bv_val[i];
2157
2158                 if( c == '$' ) {
2159                         if( len == 0 ) {
2160                                 return LDAP_INVALID_SYNTAX;
2161                         }
2162                         len = 0;
2163
2164                 } else if ( SLAP_PRINTABLE(c) ) {
2165                         len++;
2166                 } else {
2167                         return LDAP_INVALID_SYNTAX;
2168                 }
2169         }
2170
2171         if( len == 0 ) {
2172                 return LDAP_INVALID_SYNTAX;
2173         }
2174
2175         return LDAP_SUCCESS;
2176 }
2177
2178 static int
2179 IA5StringValidate(
2180         Syntax *syntax,
2181         struct berval *val )
2182 {
2183         ber_len_t i;
2184
2185         for(i=0; i < val->bv_len; i++) {
2186                 if( !LDAP_ASCII(val->bv_val[i]) ) {
2187                         return LDAP_INVALID_SYNTAX;
2188                 }
2189         }
2190
2191         return LDAP_SUCCESS;
2192 }
2193
2194 static int
2195 IA5StringNormalize(
2196         slap_mask_t use,
2197         Syntax *syntax,
2198         MatchingRule *mr,
2199         struct berval *val,
2200         struct berval *normalized,
2201         void *ctx )
2202 {
2203         char *p, *q;
2204         int casefold = !SLAP_MR_ASSOCIATED( mr,
2205                 slap_schema.si_mr_caseExactIA5Match );
2206
2207         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2208
2209         p = val->bv_val;
2210
2211         /* Ignore initial whitespace */
2212         while ( ASCII_SPACE( *p ) ) p++;
2213
2214         normalized->bv_len = val->bv_len - ( p - val->bv_val );
2215         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2216         AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2217         normalized->bv_val[normalized->bv_len] = '\0';
2218
2219         p = q = normalized->bv_val;
2220
2221         while ( *p ) {
2222                 if ( ASCII_SPACE( *p ) ) {
2223                         *q++ = *p++;
2224
2225                         /* Ignore the extra whitespace */
2226                         while ( ASCII_SPACE( *p ) ) {
2227                                 p++;
2228                         }
2229
2230                 } else if ( casefold ) {
2231                         /* Most IA5 rules require casefolding */
2232                         *q++ = TOLOWER(*p); p++;
2233
2234                 } else {
2235                         *q++ = *p++;
2236                 }
2237         }
2238
2239         assert( normalized->bv_val <= p );
2240         assert( q <= p );
2241
2242         /*
2243          * If the string ended in space, backup the pointer one
2244          * position.  One is enough because the above loop collapsed
2245          * all whitespace to a single space.
2246          */
2247         if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2248
2249         /* null terminate */
2250         *q = '\0';
2251
2252         normalized->bv_len = q - normalized->bv_val;
2253
2254         return LDAP_SUCCESS;
2255 }
2256
2257 static int
2258 UUIDValidate(
2259         Syntax *syntax,
2260         struct berval *in )
2261 {
2262         int i;
2263         if( in->bv_len != 36 ) {
2264                 return LDAP_INVALID_SYNTAX;
2265         }
2266
2267         for( i=0; i<36; i++ ) {
2268                 switch(i) {
2269                         case 8:
2270                         case 13:
2271                         case 18:
2272                         case 23:
2273                                 if( in->bv_val[i] != '-' ) {
2274                                         return LDAP_INVALID_SYNTAX;
2275                                 }
2276                                 break;
2277                         default:
2278                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2279                                         return LDAP_INVALID_SYNTAX;
2280                                 }
2281                 }
2282         }
2283         
2284         return LDAP_SUCCESS;
2285 }
2286
2287 static int
2288 UUIDPretty(
2289         Syntax *syntax,
2290         struct berval *in,
2291         struct berval *out,
2292         void *ctx )
2293 {
2294         int i;
2295         int rc=LDAP_INVALID_SYNTAX;
2296
2297         assert( in != NULL );
2298         assert( out != NULL );
2299
2300         if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2301
2302         out->bv_len = 36;
2303         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2304
2305         for( i=0; i<36; i++ ) {
2306                 switch(i) {
2307                         case 8:
2308                         case 13:
2309                         case 18:
2310                         case 23:
2311                                 if( in->bv_val[i] != '-' ) {
2312                                         goto handle_error;
2313                                 }
2314                                 out->bv_val[i] = '-';
2315                                 break;
2316
2317                         default:
2318                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2319                                         goto handle_error;
2320                                 }
2321                                 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2322                 }
2323         }
2324
2325         rc = LDAP_SUCCESS;
2326         out->bv_val[ out->bv_len ] = '\0';
2327
2328         if( 0 ) {
2329 handle_error:
2330                 slap_sl_free( out->bv_val, ctx );
2331                 out->bv_val = NULL;
2332         }
2333
2334         return rc;
2335 }
2336
2337 int
2338 UUIDNormalize(
2339         slap_mask_t usage,
2340         Syntax *syntax,
2341         MatchingRule *mr,
2342         struct berval *val,
2343         struct berval *normalized,
2344         void *ctx )
2345 {
2346         unsigned char octet = '\0';
2347         int i;
2348         int j;
2349         normalized->bv_len = 16;
2350         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2351
2352         for( i=0, j=0; i<36; i++ ) {
2353                 unsigned char nibble;
2354                 if( val->bv_val[i] == '-' ) {
2355                         continue;
2356
2357                 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2358                         nibble = val->bv_val[i] - '0';
2359
2360                 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2361                         nibble = val->bv_val[i] - ('a'-10);
2362
2363                 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2364                         nibble = val->bv_val[i] - ('A'-10);
2365
2366                 } else {
2367                         slap_sl_free( normalized->bv_val, ctx );
2368                         return LDAP_INVALID_SYNTAX;
2369                 }
2370
2371                 if( j & 1 ) {
2372                         octet |= nibble;
2373                         normalized->bv_val[j>>1] = octet;
2374                 } else {
2375                         octet = nibble << 4;
2376                 }
2377                 j++;
2378         }
2379
2380         normalized->bv_val[normalized->bv_len] = 0;
2381         return LDAP_SUCCESS;
2382 }
2383
2384
2385
2386 int
2387 numericStringValidate(
2388         Syntax *syntax,
2389         struct berval *in )
2390 {
2391         ber_len_t i;
2392
2393         if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2394
2395         for(i=0; i < in->bv_len; i++) {
2396                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2397                         return LDAP_INVALID_SYNTAX;
2398                 }
2399         }
2400
2401         return LDAP_SUCCESS;
2402 }
2403
2404 static int
2405 numericStringNormalize(
2406         slap_mask_t usage,
2407         Syntax *syntax,
2408         MatchingRule *mr,
2409         struct berval *val,
2410         struct berval *normalized,
2411         void *ctx )
2412 {
2413         /* removal all spaces */
2414         char *p, *q;
2415
2416         assert( !BER_BVISEMPTY( val ) );
2417
2418         normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2419
2420         p = val->bv_val;
2421         q = normalized->bv_val;
2422
2423         while ( *p ) {
2424                 if ( ASCII_SPACE( *p ) ) {
2425                         /* Ignore whitespace */
2426                         p++;
2427                 } else {
2428                         *q++ = *p++;
2429                 }
2430         }
2431
2432         /* we should have copied no more than is in val */
2433         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2434
2435         /* null terminate */
2436         *q = '\0';
2437
2438         normalized->bv_len = q - normalized->bv_val;
2439
2440         if( BER_BVISEMPTY( normalized ) ) {
2441                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2442                 normalized->bv_val[0] = ' ';
2443                 normalized->bv_val[1] = '\0';
2444                 normalized->bv_len = 1;
2445         }
2446
2447         return LDAP_SUCCESS;
2448 }
2449
2450 /*
2451  * Integer conversion macros that will use the largest available
2452  * type.
2453  */
2454 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
2455 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
2456 # define SLAP_LONG           long long
2457 #else
2458 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
2459 # define SLAP_LONG           long
2460 #endif /* HAVE_STRTOLL ... */
2461
2462 static int
2463 integerBitAndMatch(
2464         int *matchp,
2465         slap_mask_t flags,
2466         Syntax *syntax,
2467         MatchingRule *mr,
2468         struct berval *value,
2469         void *assertedValue )
2470 {
2471         SLAP_LONG lValue, lAssertedValue;
2472
2473         errno = 0;
2474         /* safe to assume integers are NUL terminated? */
2475         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2476         if( errno == ERANGE )
2477         {
2478                 return LDAP_CONSTRAINT_VIOLATION;
2479         }
2480
2481         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2482                 NULL, 10);
2483         if( errno == ERANGE )
2484         {
2485                 return LDAP_CONSTRAINT_VIOLATION;
2486         }
2487
2488         *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2489         return LDAP_SUCCESS;
2490 }
2491
2492 static int
2493 integerBitOrMatch(
2494         int *matchp,
2495         slap_mask_t flags,
2496         Syntax *syntax,
2497         MatchingRule *mr,
2498         struct berval *value,
2499         void *assertedValue )
2500 {
2501         SLAP_LONG lValue, lAssertedValue;
2502
2503         errno = 0;
2504         /* safe to assume integers are NUL terminated? */
2505         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2506         if( errno == ERANGE )
2507         {
2508                 return LDAP_CONSTRAINT_VIOLATION;
2509         }
2510
2511         lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2512                 NULL, 10);
2513         if( errno == ERANGE )
2514         {
2515                 return LDAP_CONSTRAINT_VIOLATION;
2516         }
2517
2518         *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2519         return LDAP_SUCCESS;
2520 }
2521
2522 static int
2523 serialNumberAndIssuerValidate(
2524         Syntax *syntax,
2525         struct berval *in )
2526 {
2527         int rc;
2528         ber_len_t n;
2529         struct berval sn, i;
2530
2531         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
2532                 in->bv_val, 0, 0 );
2533
2534         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2535
2536         if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2537                 /* Parse old format */
2538                 i.bv_val = ber_bvchr( in, '$' );
2539                 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2540
2541                 sn.bv_val = in->bv_val;
2542                 sn.bv_len = i.bv_val - in->bv_val;
2543
2544                 i.bv_val++;
2545                 i.bv_len = in->bv_len - (sn.bv_len + 1);
2546
2547                 /* eat leading zeros */
2548                 for( n=0; n < (sn.bv_len-1); n++ ) {
2549                         if( sn.bv_val[n] != '0' ) break;
2550                 }
2551                 sn.bv_val += n;
2552                 sn.bv_len -= n;
2553
2554                 for( n=0; n < sn.bv_len; n++ ) {
2555                         if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2556                 }
2557
2558         } else {
2559                 /* Parse GSER format */ 
2560                 int havesn=0,haveissuer=0;
2561                 struct berval x = *in;
2562                 x.bv_val++;
2563                 x.bv_len-=2;
2564
2565                 /* eat leading spaces */
2566                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2567                         /* empty */;
2568                 }
2569
2570                 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2571                         return LDAP_INVALID_SYNTAX;
2572                 }
2573
2574                 /* should be at issuer or serialNumber NamedValue */
2575                 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2576                         /* parse issuer */
2577                         x.bv_val += STRLENOF("issuer");
2578                         x.bv_len -= STRLENOF("issuer");
2579
2580                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2581                         x.bv_val++; x.bv_len--;
2582
2583                         /* eat leading spaces */
2584                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2585                                 /* empty */;
2586                         }
2587                         
2588                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2589                         x.bv_val++; x.bv_len--;
2590
2591                         i.bv_val = x.bv_val;
2592                         i.bv_len = 0;
2593
2594                         for( ; i.bv_len < x.bv_len; ) {
2595                                 if ( i.bv_val[i.bv_len] != '"' ) {
2596                                         i.bv_len++;
2597                                         continue;
2598                                 }
2599                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
2600                                         /* double dquote */
2601                                         i.bv_len+=2;
2602                                         continue;
2603                                 }
2604                                 break;
2605                         }
2606                         x.bv_val += i.bv_len+1;
2607                         x.bv_len -= i.bv_len+1;
2608
2609                         if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2610                                 return LDAP_INVALID_SYNTAX;
2611                         }
2612
2613                         haveissuer++;
2614
2615                 } else if( strncasecmp( x.bv_val, "serialNumber",
2616                         STRLENOF("serialNumber")) == 0 )
2617                 {
2618                         /* parse serialNumber */
2619                         int neg=0;
2620                         x.bv_val += STRLENOF("serialNumber");
2621                         x.bv_len -= STRLENOF("serialNumber");
2622
2623                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2624                         x.bv_val++; x.bv_len--;
2625
2626                         /* eat leading spaces */
2627                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2628                                 /* empty */;
2629                         }
2630                         
2631                         sn.bv_val = x.bv_val;
2632                         sn.bv_len = 0;
2633
2634                         if( sn.bv_val[0] == '-' ) {
2635                                 neg++;
2636                                 sn.bv_len++;
2637                         }
2638
2639                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2640                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2641                         }
2642
2643                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2644                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2645                                 return LDAP_INVALID_SYNTAX;
2646                         }
2647
2648                         x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
2649
2650                         if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2651                                 return LDAP_INVALID_SYNTAX;
2652                         }
2653
2654                         havesn++;
2655
2656                 } else return LDAP_INVALID_SYNTAX;
2657
2658                 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2659                 x.bv_val++; x.bv_len--;
2660
2661                 /* eat spaces */
2662                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2663                         /* empty */;
2664                 }
2665
2666                 /* should be at remaining NamedValue */
2667                 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2668                         STRLENOF("issuer" )) == 0 ))
2669                 {
2670                         /* parse issuer */
2671                         x.bv_val += STRLENOF("issuer");
2672                         x.bv_len -= STRLENOF("issuer");
2673
2674                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2675                         x.bv_val++; x.bv_len--;
2676
2677                         /* eat leading spaces */
2678                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2679                                  /* empty */;
2680                         }
2681                         
2682                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2683                         x.bv_val++; x.bv_len--;
2684
2685                         i.bv_val = x.bv_val;
2686                         i.bv_len = 0;
2687
2688                         for( ; i.bv_len < x.bv_len; ) {
2689                                 if ( i.bv_val[i.bv_len] != '"' ) {
2690                                         i.bv_len++;
2691                                         continue;
2692                                 }
2693                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
2694                                         /* double dquote */
2695                                         i.bv_len+=2;
2696                                         continue;
2697                                 }
2698                                 break;
2699                         }
2700                         x.bv_val += i.bv_len+1;
2701                         x.bv_len -= i.bv_len+1;
2702
2703                 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2704                         STRLENOF("serialNumber")) == 0 ))
2705                 {
2706                         /* parse serialNumber */
2707                         int neg=0;
2708                         x.bv_val += STRLENOF("serialNumber");
2709                         x.bv_len -= STRLENOF("serialNumber");
2710
2711                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2712                         x.bv_val++; x.bv_len--;
2713
2714                         /* eat leading spaces */
2715                         for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2716                                 /* empty */;
2717                         }
2718                         
2719                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2720                         x.bv_val++; x.bv_len--;
2721
2722                         sn.bv_val = x.bv_val;
2723                         sn.bv_len = 0;
2724
2725                         if( sn.bv_val[0] == '-' ) {
2726                                 neg++;
2727                                 sn.bv_len++;
2728                         }
2729
2730                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2731                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2732                         }
2733
2734                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2735                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2736                                 return LDAP_INVALID_SYNTAX;
2737                         }
2738
2739                         x.bv_val += sn.bv_len;
2740                         x.bv_len -= sn.bv_len;
2741
2742                 } else return LDAP_INVALID_SYNTAX;
2743
2744                 /* eat trailing spaces */
2745                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2746                         /* empty */;
2747                 }
2748
2749                 /* should have no characters left... */
2750                 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
2751         }
2752
2753         /* validate DN -- doesn't handle double dquote */ 
2754         rc = dnValidate( NULL, &i );
2755         if( rc ) return LDAP_INVALID_SYNTAX;
2756
2757         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: OKAY\n",
2758                 0, 0, 0 );
2759         return LDAP_SUCCESS;
2760 }
2761
2762 int
2763 serialNumberAndIssuerPretty(
2764         Syntax *syntax,
2765         struct berval *in,
2766         struct berval *out,
2767         void *ctx )
2768 {
2769         int rc;
2770         ber_len_t n;
2771         struct berval sn, i, ni;
2772
2773         assert( in != NULL );
2774         assert( out != NULL );
2775
2776         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
2777                 in->bv_val, 0, 0 );
2778
2779         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2780
2781         if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2782                 /* Parse old format */
2783                 i.bv_val = ber_bvchr( in, '$' );
2784                 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2785
2786                 sn.bv_val = in->bv_val;
2787                 sn.bv_len = i.bv_val - in->bv_val;
2788
2789                 i.bv_val++;
2790                 i.bv_len = in->bv_len - (sn.bv_len + 1);
2791
2792                 /* eat leading zeros */
2793                 for( n=0; n < (sn.bv_len-1); n++ ) {
2794                         if( sn.bv_val[n] != '0' ) break;
2795                 }
2796                 sn.bv_val += n;
2797                 sn.bv_len -= n;
2798
2799                 for( n=0; n < sn.bv_len; n++ ) {
2800                         if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2801                 }
2802
2803         } else {
2804                 /* Parse GSER format */ 
2805                 int havesn=0,haveissuer=0;
2806                 struct berval x = *in;
2807                 x.bv_val++;
2808                 x.bv_len-=2;
2809
2810                 /* eat leading spaces */
2811                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2812                         /* empty */;
2813                 }
2814
2815                 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2816                         return LDAP_INVALID_SYNTAX;
2817                 }
2818
2819                 /* should be at issuer or serialNumber NamedValue */
2820                 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2821                         /* parse issuer */
2822                         x.bv_val += STRLENOF("issuer");
2823                         x.bv_len -= STRLENOF("issuer");
2824
2825                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2826                         x.bv_val++; x.bv_len--;
2827
2828                         /* eat leading spaces */
2829                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2830                                 /* empty */;
2831                         }
2832                         
2833                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2834                         x.bv_val++; x.bv_len--;
2835
2836                         i.bv_val = x.bv_val;
2837                         i.bv_len = 0;
2838
2839                         for( ; i.bv_len < x.bv_len; ) {
2840                                 if ( i.bv_val[i.bv_len] != '"' ) {
2841                                         i.bv_len++;
2842                                         continue;
2843                                 }
2844                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
2845                                         /* double dquote */
2846                                         i.bv_len+=2;
2847                                         continue;
2848                                 }
2849                                 break;
2850                         }
2851                         x.bv_val += i.bv_len+1;
2852                         x.bv_len -= i.bv_len+1;
2853
2854                         if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2855                                 return LDAP_INVALID_SYNTAX;
2856                         }
2857
2858                         haveissuer++;
2859
2860                 } else if( strncasecmp( x.bv_val, "serialNumber",
2861                         STRLENOF("serialNumber")) == 0 )
2862                 {
2863                         /* parse serialNumber */
2864                         int neg=0;
2865                         x.bv_val += STRLENOF("serialNumber");
2866                         x.bv_len -= STRLENOF("serialNumber");
2867
2868                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2869                         x.bv_val++; x.bv_len--;
2870
2871                         /* eat leading spaces */
2872                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2873                                 /* empty */;
2874                         }
2875                         
2876                         sn.bv_val = x.bv_val;
2877                         sn.bv_len = 0;
2878
2879                         if( sn.bv_val[0] == '-' ) {
2880                                 neg++;
2881                                 sn.bv_len++;
2882                         }
2883
2884                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2885                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2886                         }
2887
2888                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2889                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2890                                 return LDAP_INVALID_SYNTAX;
2891                         }
2892
2893                         x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
2894
2895                         if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2896                                 return LDAP_INVALID_SYNTAX;
2897                         }
2898
2899                         havesn++;
2900
2901                 } else return LDAP_INVALID_SYNTAX;
2902
2903                 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2904                 x.bv_val++; x.bv_len--;
2905
2906                 /* eat spaces */
2907                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2908                         /* empty */;
2909                 }
2910
2911                 /* should be at remaining NamedValue */
2912                 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2913                         STRLENOF("issuer" )) == 0 ))
2914                 {
2915                         /* parse issuer */
2916                         x.bv_val += STRLENOF("issuer");
2917                         x.bv_len -= STRLENOF("issuer");
2918
2919                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2920                         x.bv_val++; x.bv_len--;
2921
2922                         /* eat leading spaces */
2923                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2924                                  /* empty */;
2925                         }
2926                         
2927                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2928                         x.bv_val++; x.bv_len--;
2929
2930                         i.bv_val = x.bv_val;
2931                         i.bv_len = 0;
2932
2933                         for( ; i.bv_len < x.bv_len; ) {
2934                                 if ( i.bv_val[i.bv_len] != '"' ) {
2935                                         i.bv_len++;
2936                                         continue;
2937                                 }
2938                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
2939                                         /* double dquote */
2940                                         i.bv_len+=2;
2941                                         continue;
2942                                 }
2943                                 break;
2944                         }
2945                         x.bv_val += i.bv_len+1;
2946                         x.bv_len -= i.bv_len+1;
2947
2948                 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2949                         STRLENOF("serialNumber")) == 0 ))
2950                 {
2951                         /* parse serialNumber */
2952                         int neg=0;
2953                         x.bv_val += STRLENOF("serialNumber");
2954                         x.bv_len -= STRLENOF("serialNumber");
2955
2956                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2957                         x.bv_val++; x.bv_len--;
2958
2959                         /* eat leading spaces */
2960                         for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2961                                 /* empty */;
2962                         }
2963                         
2964                         sn.bv_val = x.bv_val;
2965                         sn.bv_len = 0;
2966
2967                         if( sn.bv_val[0] == '-' ) {
2968                                 neg++;
2969                                 sn.bv_len++;
2970                         }
2971
2972                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2973                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2974                         }
2975
2976                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2977                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2978                                 return LDAP_INVALID_SYNTAX;
2979                         }
2980
2981                         x.bv_val += sn.bv_len;
2982                         x.bv_len -= sn.bv_len;
2983
2984                 } else return LDAP_INVALID_SYNTAX;
2985
2986                 /* eat trailing spaces */
2987                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2988                         /* empty */;
2989                 }
2990
2991                 /* should have no characters left... */
2992                 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
2993
2994                 ber_dupbv_x( &ni, &i, ctx );
2995                 i = ni;
2996
2997                 /* need to handle double dquotes here */
2998         }
2999
3000         rc = dnPretty( syntax, &i, &ni, ctx );
3001
3002         if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3003                 slap_sl_free( i.bv_val, ctx );
3004         }
3005
3006         if( rc ) return LDAP_INVALID_SYNTAX;
3007
3008         /* make room from sn + "$" */
3009         out->bv_len = STRLENOF("{ serialNumber , issuer \"\" }")
3010                 + sn.bv_len + ni.bv_len;
3011         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3012
3013         if( out->bv_val == NULL ) {
3014                 out->bv_len = 0;
3015                 slap_sl_free( ni.bv_val, ctx );
3016                 return LDAP_OTHER;
3017         }
3018
3019         n = 0;
3020         AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3021                 STRLENOF("{ serialNumber "));
3022         n = STRLENOF("{ serialNumber ");
3023
3024         AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3025         n += sn.bv_len;
3026
3027         AC_MEMCPY( &out->bv_val[n], ", issuer \"", STRLENOF(", issuer \""));
3028         n += STRLENOF(", issuer \"");
3029
3030         AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3031         n += ni.bv_len;
3032
3033         AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF("\" }"));
3034         n += STRLENOF("\" }");
3035
3036         out->bv_val[n] = '\0';
3037
3038         assert( n == out->bv_len );
3039
3040         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
3041                 out->bv_val, 0, 0 );
3042
3043         slap_sl_free( ni.bv_val, ctx );
3044
3045         return LDAP_SUCCESS; 
3046 }
3047
3048 /*
3049  * This routine is called by certificateExactNormalize when
3050  * certificateExactNormalize receives a search string instead of
3051  * a certificate. This routine checks if the search value is valid
3052  * and then returns the normalized value
3053  */
3054 static int
3055 serialNumberAndIssuerNormalize(
3056         slap_mask_t usage,
3057         Syntax *syntax,
3058         MatchingRule *mr,
3059         struct berval *in,
3060         struct berval *out,
3061         void *ctx )
3062 {
3063         int rc;
3064         ber_len_t n;
3065         struct berval sn, i, ni;
3066
3067         assert( in != NULL );
3068         assert( out != NULL );
3069
3070         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3071                 in->bv_val, 0, 0 );
3072
3073         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3074
3075         if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3076                 /* Parse old format */
3077                 i.bv_val = ber_bvchr( in, '$' );
3078                 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
3079
3080                 sn.bv_val = in->bv_val;
3081                 sn.bv_len = i.bv_val - in->bv_val;
3082
3083                 i.bv_val++;
3084                 i.bv_len = in->bv_len - (sn.bv_len + 1);
3085
3086                 /* eat leading zeros */
3087                 for( n=0; n < (sn.bv_len-1); n++ ) {
3088                         if( sn.bv_val[n] != '0' ) break;
3089                 }
3090                 sn.bv_val += n;
3091                 sn.bv_len -= n;
3092
3093                 for( n=0; n < sn.bv_len; n++ ) {
3094                         if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3095                 }
3096
3097         } else {
3098                 /* Parse GSER format */ 
3099                 int havesn=0,haveissuer=0;
3100                 struct berval x = *in;
3101                 x.bv_val++;
3102                 x.bv_len-=2;
3103
3104                 /* eat leading spaces */
3105                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3106                         /* empty */;
3107                 }
3108
3109                 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
3110                         return LDAP_INVALID_SYNTAX;
3111                 }
3112
3113                 /* should be at issuer or serialNumber NamedValue */
3114                 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
3115                         /* parse issuer */
3116                         x.bv_val += STRLENOF("issuer");
3117                         x.bv_len -= STRLENOF("issuer");
3118
3119                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3120                         x.bv_val++; x.bv_len--;
3121
3122                         /* eat leading spaces */
3123                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3124                                 /* empty */;
3125                         }
3126                         
3127                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3128                         x.bv_val++; x.bv_len--;
3129
3130                         i.bv_val = x.bv_val;
3131                         i.bv_len = 0;
3132
3133                         for( ; i.bv_len < x.bv_len; ) {
3134                                 if ( i.bv_val[i.bv_len] != '"' ) {
3135                                         i.bv_len++;
3136                                         continue;
3137                                 }
3138                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
3139                                         /* double dquote */
3140                                         i.bv_len+=2;
3141                                         continue;
3142                                 }
3143                                 break;
3144                         }
3145                         x.bv_val += i.bv_len+1;
3146                         x.bv_len -= i.bv_len+1;
3147
3148                         if ( x.bv_len < STRLENOF(",serialNumber 0")) {
3149                                 return LDAP_INVALID_SYNTAX;
3150                         }
3151
3152                         haveissuer++;
3153
3154                 } else if( strncasecmp( x.bv_val, "serialNumber",
3155                         STRLENOF("serialNumber")) == 0 )
3156                 {
3157                         /* parse serialNumber */
3158                         int neg=0;
3159                         x.bv_val += STRLENOF("serialNumber");
3160                         x.bv_len -= STRLENOF("serialNumber");
3161
3162                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3163                         x.bv_val++; x.bv_len--;
3164
3165                         /* eat leading spaces */
3166                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3167                                 /* empty */;
3168                         }
3169                         
3170                         sn.bv_val = x.bv_val;
3171                         sn.bv_len = 0;
3172
3173                         if( sn.bv_val[0] == '-' ) {
3174                                 neg++;
3175                                 sn.bv_len++;
3176                         }
3177
3178                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
3179                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
3180                         }
3181
3182                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
3183                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
3184                                 return LDAP_INVALID_SYNTAX;
3185                         }
3186
3187                         x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
3188
3189                         if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
3190                                 return LDAP_INVALID_SYNTAX;
3191                         }
3192
3193                         havesn++;
3194
3195                 } else return LDAP_INVALID_SYNTAX;
3196
3197                 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
3198                 x.bv_val++; x.bv_len--;
3199
3200                 /* eat spaces */
3201                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3202                         /* empty */;
3203                 }
3204
3205                 /* should be at remaining NamedValue */
3206                 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
3207                         STRLENOF("issuer" )) == 0 ))
3208                 {
3209                         /* parse issuer */
3210                         x.bv_val += STRLENOF("issuer");
3211                         x.bv_len -= STRLENOF("issuer");
3212
3213                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3214                         x.bv_val++; x.bv_len--;
3215
3216                         /* eat leading spaces */
3217                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3218                                  /* empty */;
3219                         }
3220                         
3221                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3222                         x.bv_val++; x.bv_len--;
3223
3224                         i.bv_val = x.bv_val;
3225                         i.bv_len = 0;
3226
3227                         for( ; i.bv_len < x.bv_len; ) {
3228                                 if ( i.bv_val[i.bv_len] != '"' ) {
3229                                         i.bv_len++;
3230                                         continue;
3231                                 }
3232                                 if ( i.bv_val[i.bv_len+1] == '"' ) {
3233                                         /* double dquote */
3234                                         i.bv_len+=2;
3235                                         continue;
3236                                 }
3237                                 break;
3238                         }
3239                         x.bv_val += i.bv_len+1;
3240                         x.bv_len -= i.bv_len+1;
3241
3242                 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
3243                         STRLENOF("serialNumber")) == 0 ))
3244                 {
3245                         /* parse serialNumber */
3246                         int neg=0;
3247                         x.bv_val += STRLENOF("serialNumber");
3248                         x.bv_len -= STRLENOF("serialNumber");
3249
3250                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3251                         x.bv_val++; x.bv_len--;
3252
3253                         /* eat leading spaces */
3254                         for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
3255                                 /* empty */;
3256                         }
3257                         
3258                         sn.bv_val = x.bv_val;
3259                         sn.bv_len = 0;
3260
3261                         if( sn.bv_val[0] == '-' ) {
3262                                 neg++;
3263                                 sn.bv_len++;
3264                         }
3265
3266                         for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
3267                                 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
3268                         }
3269
3270                         if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
3271                         if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
3272                                 return LDAP_INVALID_SYNTAX;
3273                         }
3274
3275                         x.bv_val += sn.bv_len;
3276                         x.bv_len -= sn.bv_len;
3277
3278                 } else return LDAP_INVALID_SYNTAX;
3279
3280                 /* eat trailing spaces */
3281                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3282                         /* empty */;
3283                 }
3284
3285                 /* should have no characters left... */
3286                 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
3287
3288                 ber_dupbv_x( &ni, &i, ctx );
3289                 i = ni;
3290
3291                 /* need to handle double dquotes here */
3292         }
3293
3294         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3295
3296         if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3297                 slap_sl_free( i.bv_val, ctx );
3298         }
3299
3300         if( rc ) return LDAP_INVALID_SYNTAX;
3301
3302         /* make room from sn + "$" */
3303         out->bv_len = STRLENOF( "{ serialNumber , issuer \"\" }" )
3304                 + sn.bv_len + ni.bv_len;
3305         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3306
3307         if( out->bv_val == NULL ) {
3308                 out->bv_len = 0;
3309                 slap_sl_free( ni.bv_val, ctx );
3310                 return LDAP_OTHER;
3311         }
3312
3313         n = 0;
3314         AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3315                 STRLENOF( "{ serialNumber " ));
3316         n = STRLENOF( "{ serialNumber " );
3317
3318         AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3319         n += sn.bv_len;
3320
3321         AC_MEMCPY( &out->bv_val[n], ", issuer \"", STRLENOF( ", issuer \"" ));
3322         n += STRLENOF( ", issuer \"" );
3323
3324         AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3325         n += ni.bv_len;
3326
3327         AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF( "\" }" ));
3328         n += STRLENOF( "\" }" );
3329
3330         out->bv_val[n] = '\0';
3331
3332         assert( n == out->bv_len );
3333
3334         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
3335                 out->bv_val, 0, 0 );
3336
3337         slap_sl_free( ni.bv_val, ctx );
3338
3339         return LDAP_SUCCESS;
3340 }
3341
3342 static int
3343 certificateExactNormalize(
3344         slap_mask_t usage,
3345         Syntax *syntax,
3346         MatchingRule *mr,
3347         struct berval *val,
3348         struct berval *normalized,
3349         void *ctx )
3350 {
3351         BerElementBuffer berbuf;
3352         BerElement *ber = (BerElement *)&berbuf;
3353         ber_tag_t tag;
3354         ber_len_t len;
3355         ber_int_t i;
3356         char serialbuf[64], *serial = serialbuf;
3357         ber_len_t seriallen;
3358         struct berval issuer_dn = BER_BVNULL, bvdn;
3359         unsigned char *p;
3360         int rc = LDAP_INVALID_SYNTAX;
3361
3362         if( BER_BVISEMPTY( val ) ) goto done;
3363
3364         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3365                 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
3366         }
3367
3368         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3369
3370         ber_init2( ber, val, LBER_USE_DER );
3371         tag = ber_skip_tag( ber, &len );        /* Signed Sequence */
3372         tag = ber_skip_tag( ber, &len );        /* Sequence */
3373         tag = ber_peek_tag( ber, &len );        /* Optional version? */
3374         if ( tag == SLAP_X509_OPT_C_VERSION ) {
3375                 tag = ber_skip_tag( ber, &len );
3376                 tag = ber_get_int( ber, &i );   /* version */
3377         }
3378
3379         /* NOTE: move the test here from certificateNormalize,
3380          * so that we can validate certs with serial longer
3381          * than sizeof(ber_int_t) */
3382         tag = ber_peek_tag( ber, &len );        /* serial */
3383         if ( len > sizeof(ber_int_t) ) {
3384                 unsigned char *ptr;
3385                 
3386                 tag = ber_skip_tag( ber, &len );
3387                 ptr = (unsigned char *)ber->ber_ptr;
3388                 ber_skip_data( ber, len );
3389
3390                 while ( ptr[0] == '\0' && len > 0 ) {
3391                         ptr++;
3392                         len--;
3393                 }
3394
3395 #if defined(USE_MP_BIGNUM)
3396                 /* TODO */
3397
3398 #elif defined(USE_MP_GMP)
3399                 /* TODO */
3400                 /* hint: use mpz_import(), mpz_get_str() */
3401
3402 #elif defined(USE_MP_LONG_LONG)
3403                 if ( len <= sizeof( unsigned long long ) ) {
3404                         unsigned long long      sn = 0;
3405                         int                     i;
3406
3407                         sn = ptr[0];
3408
3409                         for ( i = 1; i < len; i++ ) {
3410                                 sn <<= 8;
3411                                 sn += ptr[i];
3412                         }
3413
3414                         seriallen = snprintf( serialbuf, sizeof(serialbuf), "%llu", sn );
3415
3416                 } else {
3417                         /* do not accept serialNumber that requires
3418                          * more than long long */
3419                         rc = LDAP_INVALID_SYNTAX;
3420                         goto done;
3421                 }
3422
3423 #else
3424                 /* do not accept serialNumber that requires
3425                  * more than long */
3426                 rc = LDAP_INVALID_SYNTAX;
3427                 goto done;
3428 #endif
3429
3430         } else {
3431                 tag = ber_get_int( ber, &i );   /* serial */
3432                 seriallen = snprintf( serialbuf, sizeof(serialbuf), "%d", i );
3433         }
3434         tag = ber_skip_tag( ber, &len );        /* SignatureAlg */
3435         ber_skip_data( ber, len );
3436         tag = ber_peek_tag( ber, &len );        /* IssuerDN */
3437         len = ber_ptrlen( ber );
3438         bvdn.bv_val = val->bv_val + len;
3439         bvdn.bv_len = val->bv_len - len;
3440
3441         rc = dnX509normalize( &bvdn, &issuer_dn );
3442         if( rc != LDAP_SUCCESS ) goto done;
3443
3444         normalized->bv_len = STRLENOF( "{ serialNumber , issuer \"\" }" )
3445                 + seriallen + issuer_dn.bv_len;
3446         normalized->bv_val = ch_malloc(normalized->bv_len+1);
3447
3448         p = (unsigned char *)normalized->bv_val;
3449
3450         AC_MEMCPY(p, "{ serialNumber ", STRLENOF( "{ serialNumber " ));
3451         p += STRLENOF( "{ serialNumber " );
3452
3453         AC_MEMCPY(p, serial, seriallen);
3454         p += seriallen;
3455
3456         AC_MEMCPY(p, ", issuer \"", STRLENOF( ", issuer \"" ));
3457         p += STRLENOF( ", issuer \"" );
3458
3459         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
3460         p += issuer_dn.bv_len;
3461
3462         AC_MEMCPY(p, "\" }", STRLENOF( "\" }" ));
3463         p += STRLENOF( "\" }" );
3464
3465         *p = '\0';
3466
3467         Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
3468                 normalized->bv_val, NULL, NULL );
3469
3470         rc = LDAP_SUCCESS;
3471
3472 done:
3473         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3474         if ( serial != serialbuf ) ber_memfree_x( serial, ctx );
3475
3476         return rc;
3477 }
3478
3479 static int
3480 hexValidate(
3481         Syntax *syntax,
3482         struct berval *in )
3483 {
3484         int     i;
3485
3486         assert( in != NULL );
3487         assert( !BER_BVISNULL( in ) );
3488
3489         for ( i = 0; i < in->bv_len; i++ ) {
3490                 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
3491                         return LDAP_INVALID_SYNTAX;
3492                 }
3493         }
3494
3495         return LDAP_SUCCESS;
3496 }
3497
3498 /* Normalize a SID as used inside a CSN:
3499  * three-digit numeric string */
3500 static int
3501 hexNormalize(
3502         slap_mask_t usage,
3503         Syntax *syntax,
3504         MatchingRule *mr,
3505         struct berval *val,
3506         struct berval *normalized,
3507         void *ctx )
3508 {
3509         int     i;
3510
3511         assert( val != NULL );
3512         assert( normalized != NULL );
3513
3514         ber_dupbv_x( normalized, val, ctx );
3515
3516         for ( i = 0; i < normalized->bv_len; i++ ) {
3517                 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
3518                         ber_memfree_x( normalized->bv_val, ctx );
3519                         BER_BVZERO( normalized );
3520                         return LDAP_INVALID_SYNTAX;
3521                 }
3522
3523                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3524         }
3525
3526         return LDAP_SUCCESS;
3527 }
3528
3529 static int
3530 sidValidate (
3531         Syntax *syntax,
3532         struct berval *in )
3533 {
3534         assert( in != NULL );
3535         assert( !BER_BVISNULL( in ) );
3536
3537         if ( in->bv_len != 3 ) {
3538                 return LDAP_INVALID_SYNTAX;
3539         }
3540
3541         return hexValidate( NULL, in );
3542 }
3543
3544 /* Normalize a SID as used inside a CSN:
3545  * three-digit numeric string */
3546 static int
3547 sidNormalize(
3548         slap_mask_t usage,
3549         Syntax *syntax,
3550         MatchingRule *mr,
3551         struct berval *val,
3552         struct berval *normalized,
3553         void *ctx )
3554 {
3555         if ( val->bv_len != 3 ) {
3556                 return LDAP_INVALID_SYNTAX;
3557         }
3558
3559         return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
3560 }
3561
3562 static int
3563 sidPretty(
3564         Syntax *syntax,
3565         struct berval *val,
3566         struct berval *out,
3567         void *ctx )
3568 {
3569         return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3570 }
3571
3572 /* Normalize a SID as used inside a CSN, either as-is
3573  * (assertion value) or extracted from the CSN
3574  * (attribute value) */
3575 static int
3576 csnSidNormalize(
3577         slap_mask_t usage,
3578         Syntax *syntax,
3579         MatchingRule *mr,
3580         struct berval *val,
3581         struct berval *normalized,
3582         void *ctx )
3583 {
3584         struct berval   bv;
3585         char            *ptr,
3586                         buf[ 4 ];
3587
3588
3589         if ( BER_BVISEMPTY( val ) ) {
3590                 return LDAP_INVALID_SYNTAX;
3591         }
3592
3593         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3594                 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
3595         }
3596
3597         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3598
3599         ptr = ber_bvchr( val, '#' );
3600         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3601                 return LDAP_INVALID_SYNTAX;
3602         }
3603
3604         bv.bv_val = ptr + 1;
3605         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3606
3607         ptr = ber_bvchr( &bv, '#' );
3608         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3609                 return LDAP_INVALID_SYNTAX;
3610         }
3611
3612         bv.bv_val = ptr + 1;
3613         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3614                 
3615         ptr = ber_bvchr( &bv, '#' );
3616         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3617                 return LDAP_INVALID_SYNTAX;
3618         }
3619
3620         bv.bv_len = ptr - bv.bv_val;
3621
3622         if ( bv.bv_len == 2 ) {
3623                 /* OpenLDAP 2.3 SID */
3624                 buf[ 0 ] = '0';
3625                 buf[ 1 ] = bv.bv_val[ 0 ];
3626                 buf[ 2 ] = bv.bv_val[ 1 ];
3627                 buf[ 3 ] = '\0';
3628
3629                 bv.bv_val = buf;
3630                 bv.bv_len = 3;
3631         }
3632
3633         return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
3634 }
3635
3636 static int
3637 csnValidate(
3638         Syntax *syntax,
3639         struct berval *in )
3640 {
3641         struct berval   bv;
3642         char            *ptr;
3643         int             rc;
3644
3645         assert( in != NULL );
3646         assert( !BER_BVISNULL( in ) );
3647
3648         if ( BER_BVISEMPTY( in ) ) {
3649                 return LDAP_INVALID_SYNTAX;
3650         }
3651
3652         bv = *in;
3653
3654         ptr = ber_bvchr( &bv, '#' );
3655         if ( ptr == NULL || ptr - bv.bv_val == bv.bv_len ) {
3656                 return LDAP_INVALID_SYNTAX;
3657         }
3658
3659         bv.bv_len = ptr - bv.bv_val;
3660         if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
3661                 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
3662         {
3663                 return LDAP_INVALID_SYNTAX;
3664         }
3665
3666         rc = generalizedTimeValidate( NULL, &bv );
3667         if ( rc != LDAP_SUCCESS ) {
3668                 return rc;
3669         }
3670
3671         bv.bv_val = ptr + 1;
3672         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3673
3674         ptr = ber_bvchr( &bv, '#' );
3675         if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3676                 return LDAP_INVALID_SYNTAX;
3677         }
3678
3679         bv.bv_len = ptr - bv.bv_val;
3680         if ( bv.bv_len != 6 ) {
3681                 return LDAP_INVALID_SYNTAX;
3682         }
3683
3684         rc = hexValidate( NULL, &bv );
3685         if ( rc != LDAP_SUCCESS ) {
3686                 return rc;
3687         }
3688
3689         bv.bv_val = ptr + 1;
3690         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3691
3692         ptr = ber_bvchr( &bv, '#' );
3693         if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3694                 return LDAP_INVALID_SYNTAX;
3695         }
3696
3697         bv.bv_len = ptr - bv.bv_val;
3698         if ( bv.bv_len == 2 ) {
3699                 /* tolerate old 2-digit replica-id */
3700                 rc = hexValidate( NULL, &bv );
3701
3702         } else {
3703                 rc = sidValidate( NULL, &bv );
3704         }
3705         if ( rc != LDAP_SUCCESS ) {
3706                 return rc;
3707         }
3708
3709         bv.bv_val = ptr + 1;
3710         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3711
3712         if ( bv.bv_len != 6 ) {
3713                 return LDAP_INVALID_SYNTAX;
3714         }
3715
3716         return hexValidate( NULL, &bv );
3717 }
3718
3719 /* Normalize a CSN in OpenLDAP 2.3 format */
3720 static int
3721 csnNormalize23(
3722         slap_mask_t usage,
3723         Syntax *syntax,
3724         MatchingRule *mr,
3725         struct berval *val,
3726         struct berval *normalized,
3727         void *ctx )
3728 {
3729         struct berval   gt, cnt, sid, mod;
3730         char            *ptr;
3731         int             i;
3732
3733         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3734         assert( !BER_BVISEMPTY( val ) );
3735
3736         gt = *val;
3737
3738         ptr = ber_bvchr( &gt, '#' );
3739         if ( ptr == NULL || ptr - gt.bv_val == gt.bv_len ) {
3740                 return LDAP_INVALID_SYNTAX;
3741         }
3742
3743         gt.bv_len = ptr - gt.bv_val;
3744         assert( gt.bv_len == STRLENOF( "YYYYmmddHHMMSSZ" ) );
3745
3746         cnt.bv_val = ptr + 1;
3747         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3748
3749         ptr = ber_bvchr( &cnt, '#' );
3750         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3751                 return LDAP_INVALID_SYNTAX;
3752         }
3753
3754         cnt.bv_len = ptr - cnt.bv_val;
3755         assert( cnt.bv_len == STRLENOF( "000000" ) );
3756
3757         sid.bv_val = ptr + 1;
3758         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3759                 
3760         ptr = ber_bvchr( &sid, '#' );
3761         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3762                 return LDAP_INVALID_SYNTAX;
3763         }
3764
3765         sid.bv_len = ptr - sid.bv_val;
3766         assert( sid.bv_len == STRLENOF( "00" ) );
3767
3768         mod.bv_val = ptr + 1;
3769         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3770         assert( mod.bv_len == STRLENOF( "000000" ) );
3771
3772         normalized->bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
3773         normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
3774
3775         ptr = normalized->bv_val;
3776         ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
3777         ptr = lutil_strcopy( ptr, ".000000Z#" );
3778         ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
3779         *ptr++ = '#';
3780         *ptr++ = '0';
3781         for ( i = 0; i < sid.bv_len; i++ ) {
3782                 *ptr++ = TOLOWER( sid.bv_val[ i ] );
3783         }
3784         *ptr++ = '#';
3785         for ( i = 0; i < mod.bv_len; i++ ) {
3786                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
3787         }
3788         *ptr = '\0';
3789
3790         assert( ptr - normalized->bv_val == normalized->bv_len );
3791
3792         return LDAP_SUCCESS;
3793 }
3794
3795 /* Normalize a CSN */
3796 static int
3797 csnNormalize(
3798         slap_mask_t usage,
3799         Syntax *syntax,
3800         MatchingRule *mr,
3801         struct berval *val,
3802         struct berval *normalized,
3803         void *ctx )
3804 {
3805         struct berval   cnt, sid, mod;
3806         char            *ptr;
3807         int             i;
3808
3809         assert( val != NULL );
3810         assert( normalized != NULL );
3811
3812         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3813
3814         if ( BER_BVISEMPTY( val ) ) {
3815                 return LDAP_INVALID_SYNTAX;
3816         }
3817
3818         if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
3819                 /* Openldap <= 2.3 */
3820
3821                 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
3822         }
3823
3824         assert( val->bv_len == STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) );
3825
3826         ptr = ber_bvchr( val, '#' );
3827         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3828                 return LDAP_INVALID_SYNTAX;
3829         }
3830
3831         assert( ptr - val->bv_val == STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) );
3832
3833         cnt.bv_val = ptr + 1;
3834         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3835
3836         ptr = ber_bvchr( &cnt, '#' );
3837         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3838                 return LDAP_INVALID_SYNTAX;
3839         }
3840
3841         assert( ptr - cnt.bv_val == STRLENOF( "000000" ) );
3842
3843         sid.bv_val = ptr + 1;
3844         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3845                 
3846         ptr = ber_bvchr( &sid, '#' );
3847         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3848                 return LDAP_INVALID_SYNTAX;
3849         }
3850
3851         sid.bv_len = ptr - sid.bv_val;
3852         assert( sid.bv_len == STRLENOF( "000" ) );
3853
3854         mod.bv_val = ptr + 1;
3855         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3856
3857         assert( mod.bv_len == STRLENOF( "000000" ) );
3858
3859         ber_dupbv_x( normalized, val, ctx );
3860
3861         for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
3862                 i < normalized->bv_len; i++ )
3863         {
3864                 /* assume it's already validated that's all hex digits */
3865                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3866         }
3867
3868         return LDAP_SUCCESS;
3869 }
3870
3871 static int
3872 csnPretty(
3873         Syntax *syntax,
3874         struct berval *val,
3875         struct berval *out,
3876         void *ctx )
3877 {
3878         return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3879 }
3880
3881 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
3882 /* slight optimization - does not need the start parameter */
3883 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
3884 enum { start = 0 };
3885 #endif
3886
3887 static int
3888 check_time_syntax (struct berval *val,
3889         int start,
3890         int *parts,
3891         struct berval *fraction)
3892 {
3893         /*
3894          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
3895          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
3896          * GeneralizedTime supports leap seconds, UTCTime does not.
3897          */
3898         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
3899         static const int mdays[2][12] = {
3900                 /* non-leap years */
3901                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
3902                 /* leap years */
3903                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
3904         };
3905         char *p, *e;
3906         int part, c, c1, c2, tzoffset, leapyear = 0;
3907
3908         p = val->bv_val;
3909         e = p + val->bv_len;
3910
3911 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3912         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
3913 #endif
3914         for (part = start; part < 7 && p < e; part++) {
3915                 c1 = *p;
3916                 if (!ASCII_DIGIT(c1)) {
3917                         break;
3918                 }
3919                 p++;
3920                 if (p == e) {
3921                         return LDAP_INVALID_SYNTAX;
3922                 }
3923                 c = *p++;
3924                 if (!ASCII_DIGIT(c)) {
3925                         return LDAP_INVALID_SYNTAX;
3926                 }
3927                 c += c1 * 10 - '0' * 11;
3928                 if ((part | 1) == 3) {
3929                         --c;
3930                         if (c < 0) {
3931                                 return LDAP_INVALID_SYNTAX;
3932                         }
3933                 }
3934                 if (c >= ceiling[part]) {
3935                         if (! (c == 60 && part == 6 && start == 0))
3936                                 return LDAP_INVALID_SYNTAX;
3937                 }
3938                 parts[part] = c;
3939         }
3940         if (part < 5 + start) {
3941                 return LDAP_INVALID_SYNTAX;
3942         }
3943         for (; part < 9; part++) {
3944                 parts[part] = 0;
3945         }
3946
3947         /* leapyear check for the Gregorian calendar (year>1581) */
3948         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
3949                 leapyear = 1;
3950         }
3951
3952         if (parts[3] >= mdays[leapyear][parts[2]]) {
3953                 return LDAP_INVALID_SYNTAX;
3954         }
3955
3956         if (start == 0) {
3957                 fraction->bv_val = p;
3958                 fraction->bv_len = 0;
3959                 if (p < e && (*p == '.' || *p == ',')) {
3960                         char *end_num;
3961                         while (++p < e && ASCII_DIGIT(*p)) {
3962                                 /* EMTPY */;
3963                         }
3964                         if (p - fraction->bv_val == 1) {
3965                                 return LDAP_INVALID_SYNTAX;
3966                         }
3967                         for (end_num = p; end_num[-1] == '0'; --end_num) {
3968                                 /* EMPTY */;
3969                         }
3970                         c = end_num - fraction->bv_val;
3971                         if (c != 1) fraction->bv_len = c;
3972                 }
3973         }
3974
3975         if (p == e) {
3976                 /* no time zone */
3977                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3978         }
3979
3980         tzoffset = *p++;
3981         switch (tzoffset) {
3982         default:
3983                 return LDAP_INVALID_SYNTAX;
3984         case 'Z':
3985                 /* UTC */
3986                 break;
3987         case '+':
3988         case '-':
3989                 for (part = 7; part < 9 && p < e; part++) {
3990                         c1 = *p;
3991                         if (!ASCII_DIGIT(c1)) {
3992                                 break;
3993                         }
3994                         p++;
3995                         if (p == e) {
3996                                 return LDAP_INVALID_SYNTAX;
3997                         }
3998                         c2 = *p++;
3999                         if (!ASCII_DIGIT(c2)) {
4000                                 return LDAP_INVALID_SYNTAX;
4001                         }
4002                         parts[part] = c1 * 10 + c2 - '0' * 11;
4003                         if (parts[part] >= ceiling[part]) {
4004                                 return LDAP_INVALID_SYNTAX;
4005                         }
4006                 }
4007                 if (part < 8 + start) {
4008                         return LDAP_INVALID_SYNTAX;
4009                 }
4010
4011                 if (tzoffset == '-') {
4012                         /* negative offset to UTC, ie west of Greenwich */
4013                         parts[4] += parts[7];
4014                         parts[5] += parts[8];
4015                         /* offset is just hhmm, no seconds */
4016                         for (part = 6; --part >= 0; ) {
4017                                 if (part != 3) {
4018                                         c = ceiling[part];
4019                                 } else {
4020                                         c = mdays[leapyear][parts[2]];
4021                                 }
4022                                 if (parts[part] >= c) {
4023                                         if (part == 0) {
4024                                                 return LDAP_INVALID_SYNTAX;
4025                                         }
4026                                         parts[part] -= c;
4027                                         parts[part - 1]++;
4028                                         continue;
4029                                 } else if (part != 5) {
4030                                         break;
4031                                 }
4032                         }
4033                 } else {
4034                         /* positive offset to UTC, ie east of Greenwich */
4035                         parts[4] -= parts[7];
4036                         parts[5] -= parts[8];
4037                         for (part = 6; --part >= 0; ) {
4038                                 if (parts[part] < 0) {
4039                                         if (part == 0) {
4040                                                 return LDAP_INVALID_SYNTAX;
4041                                         }
4042                                         if (part != 3) {
4043                                                 c = ceiling[part];
4044                                         } else {
4045                                                 /* make first arg to % non-negative */
4046                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
4047                                         }
4048                                         parts[part] += c;
4049                                         parts[part - 1]--;
4050                                         continue;
4051                                 } else if (part != 5) {
4052                                         break;
4053                                 }
4054                         }
4055                 }
4056         }
4057
4058         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
4059 }
4060
4061 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4062
4063 #if 0
4064 static int
4065 xutcTimeNormalize(
4066         Syntax *syntax,
4067         struct berval *val,
4068         struct berval *normalized )
4069 {
4070         int parts[9], rc;
4071
4072         rc = check_time_syntax(val, 1, parts, NULL);
4073         if (rc != LDAP_SUCCESS) {
4074                 return rc;
4075         }
4076
4077         normalized->bv_val = ch_malloc( 14 );
4078         if ( normalized->bv_val == NULL ) {
4079                 return LBER_ERROR_MEMORY;
4080         }
4081
4082         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
4083                 parts[1], parts[2] + 1, parts[3] + 1,
4084                 parts[4], parts[5], parts[6] );
4085         normalized->bv_len = 13;
4086
4087         return LDAP_SUCCESS;
4088 }
4089 #endif /* 0 */
4090
4091 static int
4092 utcTimeValidate(
4093         Syntax *syntax,
4094         struct berval *in )
4095 {
4096         int parts[9];
4097         return check_time_syntax(in, 1, parts, NULL);
4098 }
4099
4100 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
4101
4102 static int
4103 generalizedTimeValidate(
4104         Syntax *syntax,
4105         struct berval *in )
4106 {
4107         int parts[9];
4108         struct berval fraction;
4109         return check_time_syntax(in, 0, parts, &fraction);
4110 }
4111
4112 static int
4113 generalizedTimeNormalize(
4114         slap_mask_t usage,
4115         Syntax *syntax,
4116         MatchingRule *mr,
4117         struct berval *val,
4118         struct berval *normalized,
4119         void *ctx )
4120 {
4121         int parts[9], rc;
4122         unsigned int len;
4123         struct berval fraction;
4124
4125         rc = check_time_syntax(val, 0, parts, &fraction);
4126         if (rc != LDAP_SUCCESS) {
4127                 return rc;
4128         }
4129
4130         len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
4131         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
4132         if ( BER_BVISNULL( normalized ) ) {
4133                 return LBER_ERROR_MEMORY;
4134         }
4135
4136         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
4137                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
4138                 parts[4], parts[5], parts[6] );
4139         if ( !BER_BVISEMPTY( &fraction ) ) {
4140                 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
4141                         fraction.bv_val, fraction.bv_len );
4142                 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
4143         }
4144         strcpy( normalized->bv_val + len-1, "Z" );
4145         normalized->bv_len = len;
4146
4147         return LDAP_SUCCESS;
4148 }
4149
4150 static int
4151 generalizedTimeOrderingMatch(
4152         int *matchp,
4153         slap_mask_t flags,
4154         Syntax *syntax,
4155         MatchingRule *mr,
4156         struct berval *value,
4157         void *assertedValue )
4158 {
4159         struct berval *asserted = (struct berval *) assertedValue;
4160         ber_len_t v_len  = value->bv_len;
4161         ber_len_t av_len = asserted->bv_len;
4162
4163         /* ignore trailing 'Z' when comparing */
4164         int match = memcmp( value->bv_val, asserted->bv_val,
4165                 (v_len < av_len ? v_len : av_len) - 1 );
4166         if ( match == 0 ) match = v_len - av_len;
4167
4168         *matchp = match;
4169         return LDAP_SUCCESS;
4170 }
4171
4172 /* Index generation function */
4173 int generalizedTimeIndexer(
4174         slap_mask_t use,
4175         slap_mask_t flags,
4176         Syntax *syntax,
4177         MatchingRule *mr,
4178         struct berval *prefix,
4179         BerVarray values,
4180         BerVarray *keysp,
4181         void *ctx )
4182 {
4183         int i, j;
4184         BerVarray keys;
4185         char tmp[5];
4186         BerValue bvtmp; /* 40 bit index */
4187         struct lutil_tm tm;
4188         struct lutil_timet tt;
4189
4190         bvtmp.bv_len = sizeof(tmp);
4191         bvtmp.bv_val = tmp;
4192         for( i=0; values[i].bv_val != NULL; i++ ) {
4193                 /* just count them */
4194         }
4195
4196         /* we should have at least one value at this point */
4197         assert( i > 0 );
4198
4199         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
4200
4201         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4202         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
4203                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
4204                 /* Use 40 bits of time for key */
4205                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
4206                         lutil_tm2time( &tm, &tt );
4207                         tmp[0] = tt.tt_gsec & 0xff;
4208                         tmp[4] = tt.tt_sec & 0xff;
4209                         tt.tt_sec >>= 8;
4210                         tmp[3] = tt.tt_sec & 0xff;
4211                         tt.tt_sec >>= 8;
4212                         tmp[2] = tt.tt_sec & 0xff;
4213                         tt.tt_sec >>= 8;
4214                         tmp[1] = tt.tt_sec & 0xff;
4215                         
4216                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
4217                 }
4218         }
4219
4220         keys[j].bv_val = NULL;
4221         keys[j].bv_len = 0;
4222
4223         *keysp = keys;
4224
4225         return LDAP_SUCCESS;
4226 }
4227
4228 /* Index generation function */
4229 int generalizedTimeFilter(
4230         slap_mask_t use,
4231         slap_mask_t flags,
4232         Syntax *syntax,
4233         MatchingRule *mr,
4234         struct berval *prefix,
4235         void * assertedValue,
4236         BerVarray *keysp,
4237         void *ctx )
4238 {
4239         BerVarray keys;
4240         char tmp[5];
4241         BerValue bvtmp; /* 40 bit index */
4242         BerValue *value = (BerValue *) assertedValue;
4243         struct lutil_tm tm;
4244         struct lutil_timet tt;
4245         
4246         bvtmp.bv_len = sizeof(tmp);
4247         bvtmp.bv_val = tmp;
4248         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4249         /* Use 40 bits of time for key */
4250         if ( value->bv_val && value->bv_len >= 10 &&
4251                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
4252
4253                 lutil_tm2time( &tm, &tt );
4254                 tmp[0] = tt.tt_gsec & 0xff;
4255                 tmp[4] = tt.tt_sec & 0xff;
4256                 tt.tt_sec >>= 8;
4257                 tmp[3] = tt.tt_sec & 0xff;
4258                 tt.tt_sec >>= 8;
4259                 tmp[2] = tt.tt_sec & 0xff;
4260                 tt.tt_sec >>= 8;
4261                 tmp[1] = tt.tt_sec & 0xff;
4262
4263                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
4264                 ber_dupbv_x(keys, &bvtmp, ctx );
4265                 keys[1].bv_val = NULL;
4266                 keys[1].bv_len = 0;
4267         } else {
4268                 keys = NULL;
4269         }
4270
4271         *keysp = keys;
4272
4273         return LDAP_SUCCESS;
4274 }
4275
4276 static int
4277 deliveryMethodValidate(
4278         Syntax *syntax,
4279         struct berval *val )
4280 {
4281 #undef LENOF
4282 #define LENOF(s) (sizeof(s)-1)
4283         struct berval tmp = *val;
4284         /*
4285      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
4286          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
4287          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
4288          */
4289 again:
4290         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4291
4292         switch( tmp.bv_val[0] ) {
4293         case 'a':
4294         case 'A':
4295                 if(( tmp.bv_len >= LENOF("any") ) &&
4296                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
4297                 {
4298                         tmp.bv_len -= LENOF("any");
4299                         tmp.bv_val += LENOF("any");
4300                         break;
4301                 }
4302                 return LDAP_INVALID_SYNTAX;
4303
4304         case 'm':
4305         case 'M':
4306                 if(( tmp.bv_len >= LENOF("mhs") ) &&
4307                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
4308                 {
4309                         tmp.bv_len -= LENOF("mhs");
4310                         tmp.bv_val += LENOF("mhs");
4311                         break;
4312                 }
4313                 return LDAP_INVALID_SYNTAX;
4314
4315         case 'p':
4316         case 'P':
4317                 if(( tmp.bv_len >= LENOF("physical") ) &&
4318                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
4319                 {
4320                         tmp.bv_len -= LENOF("physical");
4321                         tmp.bv_val += LENOF("physical");
4322                         break;
4323                 }
4324                 return LDAP_INVALID_SYNTAX;
4325
4326         case 't':
4327         case 'T': /* telex or teletex or telephone */
4328                 if(( tmp.bv_len >= LENOF("telex") ) &&
4329                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
4330                 {
4331                         tmp.bv_len -= LENOF("telex");
4332                         tmp.bv_val += LENOF("telex");
4333                         break;
4334                 }
4335                 if(( tmp.bv_len >= LENOF("teletex") ) &&
4336                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
4337                 {
4338                         tmp.bv_len -= LENOF("teletex");
4339                         tmp.bv_val += LENOF("teletex");
4340                         break;
4341                 }
4342                 if(( tmp.bv_len >= LENOF("telephone") ) &&
4343                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
4344                 {
4345                         tmp.bv_len -= LENOF("telephone");
4346                         tmp.bv_val += LENOF("telephone");
4347                         break;
4348                 }
4349                 return LDAP_INVALID_SYNTAX;
4350
4351         case 'g':
4352         case 'G': /* g3fax or g4fax */
4353                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
4354                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
4355                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
4356                 {
4357                         tmp.bv_len -= LENOF("g3fax");
4358                         tmp.bv_val += LENOF("g3fax");
4359                         break;
4360                 }
4361                 return LDAP_INVALID_SYNTAX;
4362
4363         case 'i':
4364         case 'I':
4365                 if(( tmp.bv_len >= LENOF("ia5") ) &&
4366                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
4367                 {
4368                         tmp.bv_len -= LENOF("ia5");
4369                         tmp.bv_val += LENOF("ia5");
4370                         break;
4371                 }
4372                 return LDAP_INVALID_SYNTAX;
4373
4374         case 'v':
4375         case 'V':
4376                 if(( tmp.bv_len >= LENOF("videotex") ) &&
4377                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
4378                 {
4379                         tmp.bv_len -= LENOF("videotex");
4380                         tmp.bv_val += LENOF("videotex");
4381                         break;
4382                 }
4383                 return LDAP_INVALID_SYNTAX;
4384
4385         default:
4386                 return LDAP_INVALID_SYNTAX;
4387         }
4388
4389         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
4390
4391         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4392                 tmp.bv_len++;
4393                 tmp.bv_val--;
4394         }
4395         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
4396                 tmp.bv_len++;
4397                 tmp.bv_val--;
4398         } else {
4399                 return LDAP_INVALID_SYNTAX;
4400         }
4401         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4402                 tmp.bv_len++;
4403                 tmp.bv_val--;
4404         }
4405
4406         goto again;
4407 }
4408
4409 static int
4410 nisNetgroupTripleValidate(
4411         Syntax *syntax,
4412         struct berval *val )
4413 {
4414         char *p, *e;
4415         int commas = 0;
4416
4417         if ( BER_BVISEMPTY( val ) ) {
4418                 return LDAP_INVALID_SYNTAX;
4419         }
4420
4421         p = (char *)val->bv_val;
4422         e = p + val->bv_len;
4423
4424         if ( *p != '(' /*')'*/ ) {
4425                 return LDAP_INVALID_SYNTAX;
4426         }
4427
4428         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
4429                 if ( *p == ',' ) {
4430                         commas++;
4431                         if ( commas > 2 ) {
4432                                 return LDAP_INVALID_SYNTAX;
4433                         }
4434
4435                 } else if ( !AD_CHAR( *p ) ) {
4436                         return LDAP_INVALID_SYNTAX;
4437                 }
4438         }
4439
4440         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
4441                 return LDAP_INVALID_SYNTAX;
4442         }
4443
4444         p++;
4445
4446         if (p != e) {
4447                 return LDAP_INVALID_SYNTAX;
4448         }
4449
4450         return LDAP_SUCCESS;
4451 }
4452
4453 static int
4454 bootParameterValidate(
4455         Syntax *syntax,
4456         struct berval *val )
4457 {
4458         char *p, *e;
4459
4460         if ( BER_BVISEMPTY( val ) ) {
4461                 return LDAP_INVALID_SYNTAX;
4462         }
4463
4464         p = (char *)val->bv_val;
4465         e = p + val->bv_len;
4466
4467         /* key */
4468         for (; ( p < e ) && ( *p != '=' ); p++ ) {
4469                 if ( !AD_CHAR( *p ) ) {
4470                         return LDAP_INVALID_SYNTAX;
4471                 }
4472         }
4473
4474         if ( *p != '=' ) {
4475                 return LDAP_INVALID_SYNTAX;
4476         }
4477
4478         /* server */
4479         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
4480                 if ( !AD_CHAR( *p ) ) {
4481                         return LDAP_INVALID_SYNTAX;
4482                 }
4483         }
4484
4485         if ( *p != ':' ) {
4486                 return LDAP_INVALID_SYNTAX;
4487         }
4488
4489         /* path */
4490         for ( p++; p < e; p++ ) {
4491                 if ( !SLAP_PRINTABLE( *p ) ) {
4492                         return LDAP_INVALID_SYNTAX;
4493                 }
4494         }
4495
4496         return LDAP_SUCCESS;
4497 }
4498
4499 static int
4500 firstComponentNormalize(
4501         slap_mask_t usage,
4502         Syntax *syntax,
4503         MatchingRule *mr,
4504         struct berval *val,
4505         struct berval *normalized,
4506         void *ctx )
4507 {
4508         int rc;
4509         struct berval comp;
4510         ber_len_t len;
4511
4512         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
4513                 ber_dupbv_x( normalized, val, ctx );
4514                 return LDAP_SUCCESS;
4515         }
4516
4517         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4518
4519         if( val->bv_val[0] != '(' /*')'*/ &&
4520                 val->bv_val[0] != '{' /*'}'*/ )
4521         {
4522                 return LDAP_INVALID_SYNTAX;
4523         }
4524
4525         /* trim leading white space */
4526         for( len=1;
4527                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
4528                 len++ )
4529         {
4530                 /* empty */
4531         }
4532
4533         /* grab next word */
4534         comp.bv_val = &val->bv_val[len];
4535         len = val->bv_len - len;
4536         for( comp.bv_len = 0;
4537                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
4538                 comp.bv_len++ )
4539         {
4540                 /* empty */
4541         }
4542
4543         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
4544                 rc = numericoidValidate( NULL, &comp );
4545         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
4546                 rc = integerValidate( NULL, &comp );
4547         } else {
4548                 rc = LDAP_INVALID_SYNTAX;
4549         }
4550         
4551
4552         if( rc == LDAP_SUCCESS ) {
4553                 ber_dupbv_x( normalized, &comp, ctx );
4554         }
4555
4556         return rc;
4557 }
4558
4559 static char *country_gen_syn[] = {
4560         "1.3.6.1.4.1.1466.115.121.1.15",
4561         "1.3.6.1.4.1.1466.115.121.1.26",
4562         "1.3.6.1.4.1.1466.115.121.1.44",
4563         NULL
4564 };
4565
4566 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
4567 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
4568
4569 static slap_syntax_defs_rec syntax_defs[] = {
4570         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
4571                 X_BINARY X_NOT_H_R ")",
4572                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
4573         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
4574                 0, NULL, NULL, NULL},
4575         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
4576                 0, NULL, NULL, NULL},
4577         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
4578                 X_NOT_H_R ")",
4579                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4580         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
4581                 X_NOT_H_R ")",
4582                 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4583         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
4584                 0, NULL, bitStringValidate, NULL },
4585         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
4586                 0, NULL, booleanValidate, NULL},
4587         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
4588                 X_BINARY X_NOT_H_R ")",
4589                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4590                 NULL, certificateValidate, NULL},
4591         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
4592                 X_BINARY X_NOT_H_R ")",
4593                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4594                 NULL, certificateListValidate, NULL},
4595         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4596                 X_BINARY X_NOT_H_R ")",
4597                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4598                 NULL, sequenceValidate, NULL},
4599 #if 0   /* need to go __after__ printableString */
4600         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4601                 0, "1.3.6.1.4.1.1466.115.121.1.44",
4602                 countryStringValidate, NULL},
4603 #endif
4604         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4605                 0, NULL, dnValidate, dnPretty},
4606         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
4607                 0, NULL, rdnValidate, rdnPretty},
4608 #ifdef LDAP_COMP_MATCH
4609         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
4610                 0, NULL, allComponentsValidate, NULL},
4611         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
4612                 0, NULL, componentFilterValidate, NULL},
4613 #endif
4614         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4615                 0, NULL, NULL, NULL},
4616         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4617                 0, NULL, deliveryMethodValidate, NULL},
4618         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4619                 0, NULL, UTF8StringValidate, NULL},
4620         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4621                 0, NULL, NULL, NULL},
4622         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4623                 0, NULL, NULL, NULL},
4624         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4625                 0, NULL, NULL, NULL},
4626         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4627                 0, NULL, NULL, NULL},
4628         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4629                 0, NULL, NULL, NULL},
4630         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4631                 0, NULL, printablesStringValidate, NULL},
4632         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4633                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
4634         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4635                 0, NULL, generalizedTimeValidate, NULL},
4636         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4637                 0, NULL, NULL, NULL},
4638         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4639                 0, NULL, IA5StringValidate, NULL},
4640         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4641                 0, NULL, integerValidate, NULL},
4642         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4643                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4644         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4645                 0, NULL, NULL, NULL},
4646         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4647                 0, NULL, NULL, NULL},
4648         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4649                 0, NULL, NULL, NULL},
4650         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4651                 0, NULL, NULL, NULL},
4652         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4653                 0, NULL, NULL, NULL},
4654         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4655                 0, NULL, nameUIDValidate, nameUIDPretty },
4656         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4657                 0, NULL, NULL, NULL},
4658         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4659                 0, NULL, numericStringValidate, NULL},
4660         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4661                 0, NULL, NULL, NULL},
4662         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4663                 0, NULL, numericoidValidate, NULL},
4664         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4665                 0, NULL, IA5StringValidate, NULL},
4666         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4667                 0, NULL, blobValidate, NULL},
4668         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4669                 0, NULL, UTF8StringValidate, NULL},
4670         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4671                 0, NULL, NULL, NULL},
4672         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4673                 0, NULL, NULL, NULL},
4674         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4675                 0, NULL, printableStringValidate, NULL},
4676         /* moved here because now depends on Directory String, IA5 String 
4677          * and Printable String */
4678         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4679                 0, country_gen_syn, countryStringValidate, NULL},
4680         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
4681 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
4682                 0, NULL, subtreeSpecificationValidate, NULL},
4683         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4684                 X_BINARY X_NOT_H_R ")",
4685                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4686         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4687                 0, NULL, printableStringValidate, NULL},
4688         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4689                 0, NULL, NULL, NULL},
4690         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4691                 0, NULL, printablesStringValidate, NULL},
4692 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4693         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4694                 0, NULL, utcTimeValidate, NULL},
4695 #endif
4696         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4697                 0, NULL, NULL, NULL},
4698         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4699                 0, NULL, NULL, NULL},
4700         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4701                 0, NULL, NULL, NULL},
4702         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4703                 0, NULL, NULL, NULL},
4704         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4705                 0, NULL, NULL, NULL},
4706
4707         /* RFC 2307 NIS Syntaxes */
4708         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
4709                 0, NULL, nisNetgroupTripleValidate, NULL},
4710         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
4711                 0, NULL, bootParameterValidate, NULL},
4712
4713         /* draft-zeilenga-ldap-x509 */
4714         {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
4715                 SLAP_SYNTAX_HIDE, NULL,
4716                 serialNumberAndIssuerValidate,
4717                 serialNumberAndIssuerPretty},
4718         {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
4719                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4720         {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
4721                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4722         {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
4723                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4724         {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
4725                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4726         {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
4727                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4728         {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
4729                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4730
4731 #ifdef SLAPD_AUTHPASSWD
4732         /* needs updating */
4733         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4734                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4735 #endif
4736
4737         {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
4738                 0, NULL, UUIDValidate, UUIDPretty},
4739
4740         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
4741                 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
4742
4743         {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
4744                 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
4745
4746         /* OpenLDAP Void Syntax */
4747         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4748                 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
4749
4750         /* FIXME: OID is unused, but not registered yet */
4751         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
4752                 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
4753
4754         {NULL, 0, NULL, NULL, NULL}
4755 };
4756
4757 char *csnSIDMatchSyntaxes[] = {
4758         "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
4759         NULL
4760 };
4761 char *certificateExactMatchSyntaxes[] = {
4762         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4763         NULL
4764 };
4765 #ifdef LDAP_COMP_MATCH
4766 char *componentFilterMatchSyntaxes[] = {
4767         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4768         NULL
4769 };
4770 #endif
4771 char *directoryStringSyntaxes[] = {
4772         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
4773         NULL
4774 };
4775 char *integerFirstComponentMatchSyntaxes[] = {
4776         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
4777         "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
4778         NULL
4779 };
4780 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
4781         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
4782         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
4783         "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
4784         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
4785         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
4786         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
4787         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
4788         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
4789         NULL
4790 };
4791
4792 /*
4793  * Other matching rules in X.520 that we do not use (yet):
4794  *
4795  * 2.5.13.25    uTCTimeMatch
4796  * 2.5.13.26    uTCTimeOrderingMatch
4797  * 2.5.13.31*   directoryStringFirstComponentMatch
4798  * 2.5.13.32*   wordMatch
4799  * 2.5.13.33*   keywordMatch
4800  * 2.5.13.36+   certificatePairExactMatch
4801  * 2.5.13.37+   certificatePairMatch
4802  * 2.5.13.38+   certificateListExactMatch
4803  * 2.5.13.39+   certificateListMatch
4804  * 2.5.13.40+   algorithmIdentifierMatch
4805  * 2.5.13.41*   storedPrefixMatch
4806  * 2.5.13.42    attributeCertificateMatch
4807  * 2.5.13.43    readerAndKeyIDMatch
4808  * 2.5.13.44    attributeIntegrityMatch
4809  *
4810  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
4811  * (+) described in draft-zeilenga-ldap-x509
4812  */
4813 static slap_mrule_defs_rec mrule_defs[] = {
4814         /*
4815          * EQUALITY matching rules must be listed after associated APPROX
4816          * matching rules.  So, we list all APPROX matching rules first.
4817          */
4818         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4819                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4820                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4821                 NULL, NULL, directoryStringApproxMatch,
4822                 directoryStringApproxIndexer, directoryStringApproxFilter,
4823                 NULL},
4824
4825         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4826                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4827                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4828                 NULL, NULL, IA5StringApproxMatch,
4829                 IA5StringApproxIndexer, IA5StringApproxFilter,
4830                 NULL},
4831
4832         /*
4833          * Other matching rules
4834          */
4835         
4836         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4837                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4838                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4839                 NULL, NULL, octetStringMatch,
4840                 octetStringIndexer, octetStringFilter,
4841                 NULL },
4842
4843         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4844                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4845                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4846                 NULL, dnNormalize, dnMatch,
4847                 octetStringIndexer, octetStringFilter,
4848                 NULL },
4849
4850         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
4851                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4852                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4853                 NULL, dnNormalize, dnRelativeMatch,
4854                 NULL, NULL,
4855                 NULL },
4856
4857         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
4858                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4859                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4860                 NULL, dnNormalize, dnRelativeMatch,
4861                 NULL, NULL,
4862                 NULL },
4863
4864         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
4865                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4866                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4867                 NULL, dnNormalize, dnRelativeMatch,
4868                 NULL, NULL,
4869                 NULL },
4870
4871         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
4872                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4873                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4874                 NULL, dnNormalize, dnRelativeMatch,
4875                 NULL, NULL,
4876                 NULL },
4877
4878         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
4879                 "SYNTAX 1.2.36.79672281.1.5.0 )",
4880                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4881                 NULL, rdnNormalize, rdnMatch,
4882                 octetStringIndexer, octetStringFilter,
4883                 NULL },
4884
4885 #ifdef LDAP_COMP_MATCH
4886         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
4887                 "SYNTAX 1.2.36.79672281.1.5.2 )",
4888                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
4889                 NULL, NULL , componentFilterMatch,
4890                 octetStringIndexer, octetStringFilter,
4891                 NULL },
4892
4893         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
4894                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4895                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4896                 NULL, NULL , allComponentsMatch,
4897                 octetStringIndexer, octetStringFilter,
4898                 NULL },
4899
4900         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
4901                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4902                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4903                 NULL, NULL , directoryComponentsMatch,
4904                 octetStringIndexer, octetStringFilter,
4905                 NULL },
4906 #endif
4907
4908         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4909                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4910                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4911                 NULL, UTF8StringNormalize, octetStringMatch,
4912                 octetStringIndexer, octetStringFilter,
4913                 directoryStringApproxMatchOID },
4914
4915         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4916                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4917                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4918                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4919                 NULL, NULL,
4920                 "caseIgnoreMatch" },
4921
4922         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4923                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4924                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4925                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4926                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4927                 "caseIgnoreMatch" },
4928
4929         {"( 2.5.13.5 NAME 'caseExactMatch' "
4930                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4931                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4932                 NULL, UTF8StringNormalize, octetStringMatch,
4933                 octetStringIndexer, octetStringFilter,
4934                 directoryStringApproxMatchOID },
4935
4936         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4937                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4938                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4939                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4940                 NULL, NULL,
4941                 "caseExactMatch" },
4942
4943         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4944                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4945                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4946                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4947                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4948                 "caseExactMatch" },
4949
4950         {"( 2.5.13.8 NAME 'numericStringMatch' "
4951                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4952                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4953                 NULL, numericStringNormalize, octetStringMatch,
4954                 octetStringIndexer, octetStringFilter,
4955                 NULL },
4956
4957         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
4958                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4959                 SLAP_MR_ORDERING, NULL,
4960                 NULL, numericStringNormalize, octetStringOrderingMatch,
4961                 NULL, NULL,
4962                 "numericStringMatch" },
4963
4964         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4965                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4966                 SLAP_MR_SUBSTR, NULL,
4967                 NULL, numericStringNormalize, octetStringSubstringsMatch,
4968                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4969                 "numericStringMatch" },
4970
4971         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4972                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4973                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4974                 NULL, NULL, NULL, NULL, NULL, NULL },
4975
4976         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4977                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4978                 SLAP_MR_SUBSTR, NULL,
4979                 NULL, NULL, NULL, NULL, NULL,
4980                 "caseIgnoreListMatch" },
4981
4982         {"( 2.5.13.13 NAME 'booleanMatch' "
4983                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
4984                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4985                 NULL, NULL, booleanMatch,
4986                 octetStringIndexer, octetStringFilter,
4987                 NULL },
4988
4989         {"( 2.5.13.14 NAME 'integerMatch' "
4990                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4991                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4992                 NULL, NULL, integerMatch,
4993                 octetStringIndexer, octetStringFilter,
4994                 NULL },
4995
4996         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
4997                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4998                 SLAP_MR_ORDERING, NULL,
4999                 NULL, NULL, integerMatch,
5000                 NULL, NULL,
5001                 "integerMatch" },
5002
5003         {"( 2.5.13.16 NAME 'bitStringMatch' "
5004                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
5005                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5006                 NULL, NULL, octetStringMatch,
5007                 octetStringIndexer, octetStringFilter,
5008                 NULL },
5009
5010         {"( 2.5.13.17 NAME 'octetStringMatch' "
5011                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5012                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5013                 NULL, NULL, octetStringMatch,
5014                 octetStringIndexer, octetStringFilter,
5015                 NULL },
5016
5017         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
5018                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5019                 SLAP_MR_ORDERING, NULL,
5020                 NULL, NULL, octetStringOrderingMatch,
5021                 NULL, NULL,
5022                 "octetStringMatch" },
5023
5024         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
5025                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5026                 SLAP_MR_SUBSTR, NULL,
5027                 NULL, NULL, octetStringSubstringsMatch,
5028                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5029                 "octetStringMatch" },
5030
5031         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
5032                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
5033                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5034                 NULL,
5035                 telephoneNumberNormalize, octetStringMatch,
5036                 octetStringIndexer, octetStringFilter,
5037                 NULL },
5038
5039         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
5040                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
5041                 SLAP_MR_SUBSTR, NULL,
5042                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
5043                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5044                 "telephoneNumberMatch" },
5045
5046         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
5047                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
5048                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5049                 NULL, NULL, NULL, NULL, NULL, NULL },
5050
5051         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
5052                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
5053                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5054                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
5055                 uniqueMemberIndexer, uniqueMemberFilter,
5056                 NULL },
5057
5058         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
5059                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
5060                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5061                 NULL, NULL, NULL, NULL, NULL, NULL },
5062
5063         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
5064                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
5065                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
5066                 NULL, generalizedTimeNormalize, octetStringMatch,
5067                 generalizedTimeIndexer, generalizedTimeFilter,
5068                 NULL },
5069
5070         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
5071                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
5072                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5073                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
5074                 NULL, NULL,
5075                 "generalizedTimeMatch" },
5076
5077         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
5078                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5079                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
5080                         integerFirstComponentMatchSyntaxes,
5081                 NULL, firstComponentNormalize, integerMatch,
5082                 octetStringIndexer, octetStringFilter,
5083                 NULL },
5084
5085         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
5086                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
5087                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
5088                         objectIdentifierFirstComponentMatchSyntaxes,
5089                 NULL, firstComponentNormalize, octetStringMatch,
5090                 octetStringIndexer, octetStringFilter,
5091                 NULL },
5092
5093         {"( 2.5.13.34 NAME 'certificateExactMatch' "
5094                 "SYNTAX 1.3.6.1.1.15.1 )",
5095                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
5096                 NULL, certificateExactNormalize, octetStringMatch,
5097                 octetStringIndexer, octetStringFilter,
5098                 NULL },
5099
5100         {"( 2.5.13.35 NAME 'certificateMatch' "
5101                 "SYNTAX 1.3.6.1.1.15.2 )",
5102                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5103                 NULL, NULL, NULL, NULL, NULL,
5104                 NULL },
5105
5106         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
5107                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5108                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5109                 NULL, IA5StringNormalize, octetStringMatch,
5110                 octetStringIndexer, octetStringFilter,
5111                 IA5StringApproxMatchOID },
5112
5113         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
5114                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5115                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5116                 NULL, IA5StringNormalize, octetStringMatch,
5117                 octetStringIndexer, octetStringFilter,
5118                 IA5StringApproxMatchOID },
5119
5120         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
5121                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5122                 SLAP_MR_SUBSTR, NULL,
5123                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
5124                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5125                 "caseIgnoreIA5Match" },
5126
5127         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
5128                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5129                 SLAP_MR_SUBSTR, NULL,
5130                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
5131                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5132                 "caseExactIA5Match" },
5133
5134 #ifdef SLAPD_AUTHPASSWD
5135         /* needs updating */
5136         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
5137                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5138                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5139                 NULL, NULL, authPasswordMatch,
5140                 NULL, NULL,
5141                 NULL},
5142 #endif
5143
5144         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
5145                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5146                 SLAP_MR_EXT, NULL,
5147                 NULL, NULL, integerBitAndMatch,
5148                 NULL, NULL,
5149                 "integerMatch" },
5150
5151         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
5152                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5153                 SLAP_MR_EXT, NULL,
5154                 NULL, NULL, integerBitOrMatch,
5155                 NULL, NULL,
5156                 "integerMatch" },
5157
5158         {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
5159                 "SYNTAX 1.3.6.1.1.16.1 )",
5160                 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
5161                 NULL, UUIDNormalize, octetStringMatch,
5162                 octetStringIndexer, octetStringFilter,
5163                 NULL},
5164
5165         {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
5166                 "SYNTAX 1.3.6.1.1.16.1 )",
5167                 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
5168                 NULL, UUIDNormalize, octetStringOrderingMatch,
5169                 octetStringIndexer, octetStringFilter,
5170                 "UUIDMatch"},
5171
5172         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
5173                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5174                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
5175                 NULL, csnNormalize, csnMatch,
5176                 csnIndexer, csnFilter,
5177                 NULL},
5178
5179         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
5180                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5181                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5182                 NULL, NULL, csnOrderingMatch,
5183                 NULL, NULL,
5184                 "CSNMatch" },
5185
5186         {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
5187                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
5188                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
5189                 NULL, csnSidNormalize, octetStringMatch,
5190                 octetStringIndexer, octetStringFilter,
5191                 NULL },
5192
5193         /* FIXME: OID is unused, but not registered yet */
5194         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
5195                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
5196                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5197                 NULL, authzNormalize, authzMatch,
5198                 NULL, NULL,
5199                 NULL},
5200
5201         {NULL, SLAP_MR_NONE, NULL,
5202                 NULL, NULL, NULL, NULL, NULL,
5203                 NULL }
5204 };
5205
5206 int
5207 slap_schema_init( void )
5208 {
5209         int             res;
5210         int             i;
5211
5212         /* we should only be called once (from main) */
5213         assert( schema_init_done == 0 );
5214
5215         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
5216                 res = register_syntax( &syntax_defs[i] );
5217
5218                 if ( res ) {
5219                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
5220                                  syntax_defs[i].sd_desc );
5221                         return LDAP_OTHER;
5222                 }
5223         }
5224
5225         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
5226                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
5227                         mrule_defs[i].mrd_compat_syntaxes == NULL )
5228                 {
5229                         fprintf( stderr,
5230                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
5231                                  mrule_defs[i].mrd_desc );
5232                         continue;
5233                 }
5234
5235                 res = register_matching_rule( &mrule_defs[i] );
5236
5237                 if ( res ) {
5238                         fprintf( stderr,
5239                                 "slap_schema_init: Error registering matching rule %s\n",
5240                                  mrule_defs[i].mrd_desc );
5241                         return LDAP_OTHER;
5242                 }
5243         }
5244
5245         res = slap_schema_load();
5246         schema_init_done = 1;
5247         return res;
5248 }
5249
5250 void
5251 schema_destroy( void )
5252 {
5253         oidm_destroy();
5254         oc_destroy();
5255         at_destroy();
5256         mr_destroy();
5257         mru_destroy();
5258         syn_destroy();
5259
5260         if( schema_init_done ) {
5261                 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
5262                 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
5263         }
5264 }