]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
fix one-time leak (coverity)
[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         ber_dupbv_x( normalized, val, ctx );
3512
3513         for ( i = 0; i < normalized->bv_len; i++ ) {
3514                 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
3515                         ber_memfree_x( normalized->bv_val, ctx );
3516                         BER_BVZERO( normalized );
3517                         return LDAP_INVALID_SYNTAX;
3518                 }
3519
3520                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3521         }
3522
3523         return LDAP_SUCCESS;
3524 }
3525
3526 static int
3527 sidValidate (
3528         Syntax *syntax,
3529         struct berval *in )
3530 {
3531         assert( in != NULL );
3532         assert( !BER_BVISNULL( in ) );
3533
3534         if ( in->bv_len != 3 ) {
3535                 return LDAP_INVALID_SYNTAX;
3536         }
3537
3538         return hexValidate( NULL, in );
3539 }
3540
3541 /* Normalize a SID as used inside a CSN:
3542  * three-digit numeric string */
3543 static int
3544 sidNormalize(
3545         slap_mask_t usage,
3546         Syntax *syntax,
3547         MatchingRule *mr,
3548         struct berval *val,
3549         struct berval *normalized,
3550         void *ctx )
3551 {
3552         if ( val->bv_len != 3 ) {
3553                 return LDAP_INVALID_SYNTAX;
3554         }
3555
3556         return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
3557 }
3558
3559 static int
3560 sidPretty(
3561         Syntax *syntax,
3562         struct berval *val,
3563         struct berval *out,
3564         void *ctx )
3565 {
3566         return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3567 }
3568
3569 /* Normalize a SID as used inside a CSN, either as-is
3570  * (assertion value) or extracted from the CSN
3571  * (attribute value) */
3572 static int
3573 csnSidNormalize(
3574         slap_mask_t usage,
3575         Syntax *syntax,
3576         MatchingRule *mr,
3577         struct berval *val,
3578         struct berval *normalized,
3579         void *ctx )
3580 {
3581         struct berval   bv;
3582         char            *ptr,
3583                         buf[ 4 ];
3584
3585
3586         if ( BER_BVISEMPTY( val ) ) {
3587                 return LDAP_INVALID_SYNTAX;
3588         }
3589
3590         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3591                 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
3592         }
3593
3594         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3595
3596         ptr = ber_bvchr( val, '#' );
3597         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3598                 return LDAP_INVALID_SYNTAX;
3599         }
3600
3601         bv.bv_val = ptr + 1;
3602         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3603
3604         ptr = ber_bvchr( &bv, '#' );
3605         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3606                 return LDAP_INVALID_SYNTAX;
3607         }
3608
3609         bv.bv_val = ptr + 1;
3610         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3611                 
3612         ptr = ber_bvchr( &bv, '#' );
3613         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3614                 return LDAP_INVALID_SYNTAX;
3615         }
3616
3617         bv.bv_len = ptr - bv.bv_val;
3618
3619         if ( bv.bv_len == 2 ) {
3620                 /* OpenLDAP 2.3 SID */
3621                 buf[ 0 ] = '0';
3622                 buf[ 1 ] = bv.bv_val[ 0 ];
3623                 buf[ 2 ] = bv.bv_val[ 1 ];
3624                 buf[ 3 ] = '\0';
3625
3626                 bv.bv_val = buf;
3627                 bv.bv_len = 3;
3628         }
3629
3630         return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
3631 }
3632
3633 static int
3634 csnValidate(
3635         Syntax *syntax,
3636         struct berval *in )
3637 {
3638         struct berval   bv;
3639         char            *ptr;
3640         int             rc;
3641
3642         assert( in != NULL );
3643         assert( !BER_BVISNULL( in ) );
3644
3645         if ( BER_BVISEMPTY( in ) ) {
3646                 return LDAP_INVALID_SYNTAX;
3647         }
3648
3649         bv = *in;
3650
3651         ptr = ber_bvchr( &bv, '#' );
3652         if ( ptr == NULL || ptr - bv.bv_val == bv.bv_len ) {
3653                 return LDAP_INVALID_SYNTAX;
3654         }
3655
3656         bv.bv_len = ptr - bv.bv_val;
3657         if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
3658                 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
3659         {
3660                 return LDAP_INVALID_SYNTAX;
3661         }
3662
3663         rc = generalizedTimeValidate( NULL, &bv );
3664         if ( rc != LDAP_SUCCESS ) {
3665                 return rc;
3666         }
3667
3668         bv.bv_val = ptr + 1;
3669         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3670
3671         ptr = ber_bvchr( &bv, '#' );
3672         if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3673                 return LDAP_INVALID_SYNTAX;
3674         }
3675
3676         bv.bv_len = ptr - bv.bv_val;
3677         if ( bv.bv_len != 6 ) {
3678                 return LDAP_INVALID_SYNTAX;
3679         }
3680
3681         rc = hexValidate( NULL, &bv );
3682         if ( rc != LDAP_SUCCESS ) {
3683                 return rc;
3684         }
3685
3686         bv.bv_val = ptr + 1;
3687         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3688
3689         ptr = ber_bvchr( &bv, '#' );
3690         if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3691                 return LDAP_INVALID_SYNTAX;
3692         }
3693
3694         bv.bv_len = ptr - bv.bv_val;
3695         if ( bv.bv_len == 2 ) {
3696                 /* tolerate old 2-digit replica-id */
3697                 rc = hexValidate( NULL, &bv );
3698
3699         } else {
3700                 rc = sidValidate( NULL, &bv );
3701         }
3702         if ( rc != LDAP_SUCCESS ) {
3703                 return rc;
3704         }
3705
3706         bv.bv_val = ptr + 1;
3707         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3708
3709         if ( bv.bv_len != 6 ) {
3710                 return LDAP_INVALID_SYNTAX;
3711         }
3712
3713         return hexValidate( NULL, &bv );
3714 }
3715
3716 /* Normalize a CSN in OpenLDAP 2.3 format */
3717 static int
3718 csnNormalize23(
3719         slap_mask_t usage,
3720         Syntax *syntax,
3721         MatchingRule *mr,
3722         struct berval *val,
3723         struct berval *normalized,
3724         void *ctx )
3725 {
3726         struct berval   gt, cnt, sid, mod;
3727         char            *ptr;
3728         int             i;
3729
3730         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3731         assert( !BER_BVISEMPTY( val ) );
3732
3733         gt = *val;
3734
3735         ptr = ber_bvchr( &gt, '#' );
3736         if ( ptr == NULL || ptr - gt.bv_val == gt.bv_len ) {
3737                 return LDAP_INVALID_SYNTAX;
3738         }
3739
3740         gt.bv_len = ptr - gt.bv_val;
3741         assert( gt.bv_len == STRLENOF( "YYYYmmddHHMMSSZ" ) );
3742
3743         cnt.bv_val = ptr + 1;
3744         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3745
3746         ptr = ber_bvchr( &cnt, '#' );
3747         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3748                 return LDAP_INVALID_SYNTAX;
3749         }
3750
3751         cnt.bv_len = ptr - cnt.bv_val;
3752         assert( cnt.bv_len == STRLENOF( "000000" ) );
3753
3754         sid.bv_val = ptr + 1;
3755         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3756                 
3757         ptr = ber_bvchr( &sid, '#' );
3758         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3759                 return LDAP_INVALID_SYNTAX;
3760         }
3761
3762         sid.bv_len = ptr - sid.bv_val;
3763         assert( sid.bv_len == STRLENOF( "00" ) );
3764
3765         mod.bv_val = ptr + 1;
3766         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3767         assert( mod.bv_len == STRLENOF( "000000" ) );
3768
3769         normalized->bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
3770         normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
3771
3772         ptr = normalized->bv_val;
3773         ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
3774         ptr = lutil_strcopy( ptr, ".000000Z#" );
3775         ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
3776         *ptr++ = '#';
3777         *ptr++ = '0';
3778         for ( i = 0; i < sid.bv_len; i++ ) {
3779                 *ptr++ = TOLOWER( sid.bv_val[ i ] );
3780         }
3781         *ptr++ = '#';
3782         for ( i = 0; i < mod.bv_len; i++ ) {
3783                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
3784         }
3785         *ptr = '\0';
3786
3787         assert( ptr - normalized->bv_val == normalized->bv_len );
3788
3789         return LDAP_SUCCESS;
3790 }
3791
3792 /* Normalize a CSN */
3793 static int
3794 csnNormalize(
3795         slap_mask_t usage,
3796         Syntax *syntax,
3797         MatchingRule *mr,
3798         struct berval *val,
3799         struct berval *normalized,
3800         void *ctx )
3801 {
3802         struct berval   cnt, sid, mod;
3803         char            *ptr;
3804         int             i;
3805
3806         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3807
3808         if ( BER_BVISEMPTY( val ) ) {
3809                 return LDAP_INVALID_SYNTAX;
3810         }
3811
3812         if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
3813                 /* Openldap <= 2.3 */
3814
3815                 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
3816         }
3817
3818         assert( val->bv_len == STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) );
3819
3820         ptr = ber_bvchr( val, '#' );
3821         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3822                 return LDAP_INVALID_SYNTAX;
3823         }
3824
3825         assert( ptr - val->bv_val == STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) );
3826
3827         cnt.bv_val = ptr + 1;
3828         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3829
3830         ptr = ber_bvchr( &cnt, '#' );
3831         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3832                 return LDAP_INVALID_SYNTAX;
3833         }
3834
3835         assert( ptr - cnt.bv_val == STRLENOF( "000000" ) );
3836
3837         sid.bv_val = ptr + 1;
3838         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3839                 
3840         ptr = ber_bvchr( &sid, '#' );
3841         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3842                 return LDAP_INVALID_SYNTAX;
3843         }
3844
3845         sid.bv_len = ptr - sid.bv_val;
3846         assert( sid.bv_len == STRLENOF( "000" ) );
3847
3848         mod.bv_val = ptr + 1;
3849         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3850
3851         assert( mod.bv_len == STRLENOF( "000000" ) );
3852
3853         ber_dupbv_x( normalized, val, ctx );
3854
3855         for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
3856                 i < normalized->bv_len; i++ )
3857         {
3858                 /* assume it's already validated that's all hex digits */
3859                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3860         }
3861
3862         return LDAP_SUCCESS;
3863 }
3864
3865 static int
3866 csnPretty(
3867         Syntax *syntax,
3868         struct berval *val,
3869         struct berval *out,
3870         void *ctx )
3871 {
3872         return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3873 }
3874
3875 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
3876 /* slight optimization - does not need the start parameter */
3877 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
3878 enum { start = 0 };
3879 #endif
3880
3881 static int
3882 check_time_syntax (struct berval *val,
3883         int start,
3884         int *parts,
3885         struct berval *fraction)
3886 {
3887         /*
3888          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
3889          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
3890          * GeneralizedTime supports leap seconds, UTCTime does not.
3891          */
3892         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
3893         static const int mdays[2][12] = {
3894                 /* non-leap years */
3895                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
3896                 /* leap years */
3897                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
3898         };
3899         char *p, *e;
3900         int part, c, c1, c2, tzoffset, leapyear = 0;
3901
3902         p = val->bv_val;
3903         e = p + val->bv_len;
3904
3905 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3906         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
3907 #endif
3908         for (part = start; part < 7 && p < e; part++) {
3909                 c1 = *p;
3910                 if (!ASCII_DIGIT(c1)) {
3911                         break;
3912                 }
3913                 p++;
3914                 if (p == e) {
3915                         return LDAP_INVALID_SYNTAX;
3916                 }
3917                 c = *p++;
3918                 if (!ASCII_DIGIT(c)) {
3919                         return LDAP_INVALID_SYNTAX;
3920                 }
3921                 c += c1 * 10 - '0' * 11;
3922                 if ((part | 1) == 3) {
3923                         --c;
3924                         if (c < 0) {
3925                                 return LDAP_INVALID_SYNTAX;
3926                         }
3927                 }
3928                 if (c >= ceiling[part]) {
3929                         if (! (c == 60 && part == 6 && start == 0))
3930                                 return LDAP_INVALID_SYNTAX;
3931                 }
3932                 parts[part] = c;
3933         }
3934         if (part < 5 + start) {
3935                 return LDAP_INVALID_SYNTAX;
3936         }
3937         for (; part < 9; part++) {
3938                 parts[part] = 0;
3939         }
3940
3941         /* leapyear check for the Gregorian calendar (year>1581) */
3942         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
3943                 leapyear = 1;
3944         }
3945
3946         if (parts[3] >= mdays[leapyear][parts[2]]) {
3947                 return LDAP_INVALID_SYNTAX;
3948         }
3949
3950         if (start == 0) {
3951                 fraction->bv_val = p;
3952                 fraction->bv_len = 0;
3953                 if (p < e && (*p == '.' || *p == ',')) {
3954                         char *end_num;
3955                         while (++p < e && ASCII_DIGIT(*p)) {
3956                                 /* EMTPY */;
3957                         }
3958                         if (p - fraction->bv_val == 1) {
3959                                 return LDAP_INVALID_SYNTAX;
3960                         }
3961                         for (end_num = p; end_num[-1] == '0'; --end_num) {
3962                                 /* EMPTY */;
3963                         }
3964                         c = end_num - fraction->bv_val;
3965                         if (c != 1) fraction->bv_len = c;
3966                 }
3967         }
3968
3969         if (p == e) {
3970                 /* no time zone */
3971                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3972         }
3973
3974         tzoffset = *p++;
3975         switch (tzoffset) {
3976         default:
3977                 return LDAP_INVALID_SYNTAX;
3978         case 'Z':
3979                 /* UTC */
3980                 break;
3981         case '+':
3982         case '-':
3983                 for (part = 7; part < 9 && p < e; part++) {
3984                         c1 = *p;
3985                         if (!ASCII_DIGIT(c1)) {
3986                                 break;
3987                         }
3988                         p++;
3989                         if (p == e) {
3990                                 return LDAP_INVALID_SYNTAX;
3991                         }
3992                         c2 = *p++;
3993                         if (!ASCII_DIGIT(c2)) {
3994                                 return LDAP_INVALID_SYNTAX;
3995                         }
3996                         parts[part] = c1 * 10 + c2 - '0' * 11;
3997                         if (parts[part] >= ceiling[part]) {
3998                                 return LDAP_INVALID_SYNTAX;
3999                         }
4000                 }
4001                 if (part < 8 + start) {
4002                         return LDAP_INVALID_SYNTAX;
4003                 }
4004
4005                 if (tzoffset == '-') {
4006                         /* negative offset to UTC, ie west of Greenwich */
4007                         parts[4] += parts[7];
4008                         parts[5] += parts[8];
4009                         /* offset is just hhmm, no seconds */
4010                         for (part = 6; --part >= 0; ) {
4011                                 if (part != 3) {
4012                                         c = ceiling[part];
4013                                 } else {
4014                                         c = mdays[leapyear][parts[2]];
4015                                 }
4016                                 if (parts[part] >= c) {
4017                                         if (part == 0) {
4018                                                 return LDAP_INVALID_SYNTAX;
4019                                         }
4020                                         parts[part] -= c;
4021                                         parts[part - 1]++;
4022                                         continue;
4023                                 } else if (part != 5) {
4024                                         break;
4025                                 }
4026                         }
4027                 } else {
4028                         /* positive offset to UTC, ie east of Greenwich */
4029                         parts[4] -= parts[7];
4030                         parts[5] -= parts[8];
4031                         for (part = 6; --part >= 0; ) {
4032                                 if (parts[part] < 0) {
4033                                         if (part == 0) {
4034                                                 return LDAP_INVALID_SYNTAX;
4035                                         }
4036                                         if (part != 3) {
4037                                                 c = ceiling[part];
4038                                         } else {
4039                                                 /* make first arg to % non-negative */
4040                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
4041                                         }
4042                                         parts[part] += c;
4043                                         parts[part - 1]--;
4044                                         continue;
4045                                 } else if (part != 5) {
4046                                         break;
4047                                 }
4048                         }
4049                 }
4050         }
4051
4052         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
4053 }
4054
4055 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4056
4057 #if 0
4058 static int
4059 xutcTimeNormalize(
4060         Syntax *syntax,
4061         struct berval *val,
4062         struct berval *normalized )
4063 {
4064         int parts[9], rc;
4065
4066         rc = check_time_syntax(val, 1, parts, NULL);
4067         if (rc != LDAP_SUCCESS) {
4068                 return rc;
4069         }
4070
4071         normalized->bv_val = ch_malloc( 14 );
4072         if ( normalized->bv_val == NULL ) {
4073                 return LBER_ERROR_MEMORY;
4074         }
4075
4076         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
4077                 parts[1], parts[2] + 1, parts[3] + 1,
4078                 parts[4], parts[5], parts[6] );
4079         normalized->bv_len = 13;
4080
4081         return LDAP_SUCCESS;
4082 }
4083 #endif /* 0 */
4084
4085 static int
4086 utcTimeValidate(
4087         Syntax *syntax,
4088         struct berval *in )
4089 {
4090         int parts[9];
4091         return check_time_syntax(in, 1, parts, NULL);
4092 }
4093
4094 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
4095
4096 static int
4097 generalizedTimeValidate(
4098         Syntax *syntax,
4099         struct berval *in )
4100 {
4101         int parts[9];
4102         struct berval fraction;
4103         return check_time_syntax(in, 0, parts, &fraction);
4104 }
4105
4106 static int
4107 generalizedTimeNormalize(
4108         slap_mask_t usage,
4109         Syntax *syntax,
4110         MatchingRule *mr,
4111         struct berval *val,
4112         struct berval *normalized,
4113         void *ctx )
4114 {
4115         int parts[9], rc;
4116         unsigned int len;
4117         struct berval fraction;
4118
4119         rc = check_time_syntax(val, 0, parts, &fraction);
4120         if (rc != LDAP_SUCCESS) {
4121                 return rc;
4122         }
4123
4124         len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
4125         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
4126         if ( BER_BVISNULL( normalized ) ) {
4127                 return LBER_ERROR_MEMORY;
4128         }
4129
4130         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
4131                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
4132                 parts[4], parts[5], parts[6] );
4133         if ( !BER_BVISEMPTY( &fraction ) ) {
4134                 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
4135                         fraction.bv_val, fraction.bv_len );
4136                 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
4137         }
4138         strcpy( normalized->bv_val + len-1, "Z" );
4139         normalized->bv_len = len;
4140
4141         return LDAP_SUCCESS;
4142 }
4143
4144 static int
4145 generalizedTimeOrderingMatch(
4146         int *matchp,
4147         slap_mask_t flags,
4148         Syntax *syntax,
4149         MatchingRule *mr,
4150         struct berval *value,
4151         void *assertedValue )
4152 {
4153         struct berval *asserted = (struct berval *) assertedValue;
4154         ber_len_t v_len  = value->bv_len;
4155         ber_len_t av_len = asserted->bv_len;
4156
4157         /* ignore trailing 'Z' when comparing */
4158         int match = memcmp( value->bv_val, asserted->bv_val,
4159                 (v_len < av_len ? v_len : av_len) - 1 );
4160         if ( match == 0 ) match = v_len - av_len;
4161
4162         *matchp = match;
4163         return LDAP_SUCCESS;
4164 }
4165
4166 /* Index generation function */
4167 int generalizedTimeIndexer(
4168         slap_mask_t use,
4169         slap_mask_t flags,
4170         Syntax *syntax,
4171         MatchingRule *mr,
4172         struct berval *prefix,
4173         BerVarray values,
4174         BerVarray *keysp,
4175         void *ctx )
4176 {
4177         int i, j;
4178         BerVarray keys;
4179         char tmp[5];
4180         BerValue bvtmp; /* 40 bit index */
4181         struct lutil_tm tm;
4182         struct lutil_timet tt;
4183
4184         bvtmp.bv_len = sizeof(tmp);
4185         bvtmp.bv_val = tmp;
4186         for( i=0; values[i].bv_val != NULL; i++ ) {
4187                 /* just count them */
4188         }
4189
4190         /* we should have at least one value at this point */
4191         assert( i > 0 );
4192
4193         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
4194
4195         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4196         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
4197                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
4198                 /* Use 40 bits of time for key */
4199                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
4200                         lutil_tm2time( &tm, &tt );
4201                         tmp[0] = tt.tt_gsec & 0xff;
4202                         tmp[4] = tt.tt_sec & 0xff;
4203                         tt.tt_sec >>= 8;
4204                         tmp[3] = tt.tt_sec & 0xff;
4205                         tt.tt_sec >>= 8;
4206                         tmp[2] = tt.tt_sec & 0xff;
4207                         tt.tt_sec >>= 8;
4208                         tmp[1] = tt.tt_sec & 0xff;
4209                         
4210                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
4211                 }
4212         }
4213
4214         keys[j].bv_val = NULL;
4215         keys[j].bv_len = 0;
4216
4217         *keysp = keys;
4218
4219         return LDAP_SUCCESS;
4220 }
4221
4222 /* Index generation function */
4223 int generalizedTimeFilter(
4224         slap_mask_t use,
4225         slap_mask_t flags,
4226         Syntax *syntax,
4227         MatchingRule *mr,
4228         struct berval *prefix,
4229         void * assertedValue,
4230         BerVarray *keysp,
4231         void *ctx )
4232 {
4233         BerVarray keys;
4234         char tmp[5];
4235         BerValue bvtmp; /* 40 bit index */
4236         BerValue *value = (BerValue *) assertedValue;
4237         struct lutil_tm tm;
4238         struct lutil_timet tt;
4239         
4240         bvtmp.bv_len = sizeof(tmp);
4241         bvtmp.bv_val = tmp;
4242         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4243         /* Use 40 bits of time for key */
4244         if ( value->bv_val && value->bv_len >= 10 &&
4245                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
4246
4247                 lutil_tm2time( &tm, &tt );
4248                 tmp[0] = tt.tt_gsec & 0xff;
4249                 tmp[4] = tt.tt_sec & 0xff;
4250                 tt.tt_sec >>= 8;
4251                 tmp[3] = tt.tt_sec & 0xff;
4252                 tt.tt_sec >>= 8;
4253                 tmp[2] = tt.tt_sec & 0xff;
4254                 tt.tt_sec >>= 8;
4255                 tmp[1] = tt.tt_sec & 0xff;
4256
4257                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
4258                 ber_dupbv_x(keys, &bvtmp, ctx );
4259                 keys[1].bv_val = NULL;
4260                 keys[1].bv_len = 0;
4261         } else {
4262                 keys = NULL;
4263         }
4264
4265         *keysp = keys;
4266
4267         return LDAP_SUCCESS;
4268 }
4269
4270 static int
4271 deliveryMethodValidate(
4272         Syntax *syntax,
4273         struct berval *val )
4274 {
4275 #undef LENOF
4276 #define LENOF(s) (sizeof(s)-1)
4277         struct berval tmp = *val;
4278         /*
4279      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
4280          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
4281          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
4282          */
4283 again:
4284         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4285
4286         switch( tmp.bv_val[0] ) {
4287         case 'a':
4288         case 'A':
4289                 if(( tmp.bv_len >= LENOF("any") ) &&
4290                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
4291                 {
4292                         tmp.bv_len -= LENOF("any");
4293                         tmp.bv_val += LENOF("any");
4294                         break;
4295                 }
4296                 return LDAP_INVALID_SYNTAX;
4297
4298         case 'm':
4299         case 'M':
4300                 if(( tmp.bv_len >= LENOF("mhs") ) &&
4301                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
4302                 {
4303                         tmp.bv_len -= LENOF("mhs");
4304                         tmp.bv_val += LENOF("mhs");
4305                         break;
4306                 }
4307                 return LDAP_INVALID_SYNTAX;
4308
4309         case 'p':
4310         case 'P':
4311                 if(( tmp.bv_len >= LENOF("physical") ) &&
4312                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
4313                 {
4314                         tmp.bv_len -= LENOF("physical");
4315                         tmp.bv_val += LENOF("physical");
4316                         break;
4317                 }
4318                 return LDAP_INVALID_SYNTAX;
4319
4320         case 't':
4321         case 'T': /* telex or teletex or telephone */
4322                 if(( tmp.bv_len >= LENOF("telex") ) &&
4323                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
4324                 {
4325                         tmp.bv_len -= LENOF("telex");
4326                         tmp.bv_val += LENOF("telex");
4327                         break;
4328                 }
4329                 if(( tmp.bv_len >= LENOF("teletex") ) &&
4330                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
4331                 {
4332                         tmp.bv_len -= LENOF("teletex");
4333                         tmp.bv_val += LENOF("teletex");
4334                         break;
4335                 }
4336                 if(( tmp.bv_len >= LENOF("telephone") ) &&
4337                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
4338                 {
4339                         tmp.bv_len -= LENOF("telephone");
4340                         tmp.bv_val += LENOF("telephone");
4341                         break;
4342                 }
4343                 return LDAP_INVALID_SYNTAX;
4344
4345         case 'g':
4346         case 'G': /* g3fax or g4fax */
4347                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
4348                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
4349                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
4350                 {
4351                         tmp.bv_len -= LENOF("g3fax");
4352                         tmp.bv_val += LENOF("g3fax");
4353                         break;
4354                 }
4355                 return LDAP_INVALID_SYNTAX;
4356
4357         case 'i':
4358         case 'I':
4359                 if(( tmp.bv_len >= LENOF("ia5") ) &&
4360                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
4361                 {
4362                         tmp.bv_len -= LENOF("ia5");
4363                         tmp.bv_val += LENOF("ia5");
4364                         break;
4365                 }
4366                 return LDAP_INVALID_SYNTAX;
4367
4368         case 'v':
4369         case 'V':
4370                 if(( tmp.bv_len >= LENOF("videotex") ) &&
4371                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
4372                 {
4373                         tmp.bv_len -= LENOF("videotex");
4374                         tmp.bv_val += LENOF("videotex");
4375                         break;
4376                 }
4377                 return LDAP_INVALID_SYNTAX;
4378
4379         default:
4380                 return LDAP_INVALID_SYNTAX;
4381         }
4382
4383         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
4384
4385         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4386                 tmp.bv_len++;
4387                 tmp.bv_val--;
4388         }
4389         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
4390                 tmp.bv_len++;
4391                 tmp.bv_val--;
4392         } else {
4393                 return LDAP_INVALID_SYNTAX;
4394         }
4395         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4396                 tmp.bv_len++;
4397                 tmp.bv_val--;
4398         }
4399
4400         goto again;
4401 }
4402
4403 static int
4404 nisNetgroupTripleValidate(
4405         Syntax *syntax,
4406         struct berval *val )
4407 {
4408         char *p, *e;
4409         int commas = 0;
4410
4411         if ( BER_BVISEMPTY( val ) ) {
4412                 return LDAP_INVALID_SYNTAX;
4413         }
4414
4415         p = (char *)val->bv_val;
4416         e = p + val->bv_len;
4417
4418         if ( *p != '(' /*')'*/ ) {
4419                 return LDAP_INVALID_SYNTAX;
4420         }
4421
4422         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
4423                 if ( *p == ',' ) {
4424                         commas++;
4425                         if ( commas > 2 ) {
4426                                 return LDAP_INVALID_SYNTAX;
4427                         }
4428
4429                 } else if ( !AD_CHAR( *p ) ) {
4430                         return LDAP_INVALID_SYNTAX;
4431                 }
4432         }
4433
4434         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
4435                 return LDAP_INVALID_SYNTAX;
4436         }
4437
4438         p++;
4439
4440         if (p != e) {
4441                 return LDAP_INVALID_SYNTAX;
4442         }
4443
4444         return LDAP_SUCCESS;
4445 }
4446
4447 static int
4448 bootParameterValidate(
4449         Syntax *syntax,
4450         struct berval *val )
4451 {
4452         char *p, *e;
4453
4454         if ( BER_BVISEMPTY( val ) ) {
4455                 return LDAP_INVALID_SYNTAX;
4456         }
4457
4458         p = (char *)val->bv_val;
4459         e = p + val->bv_len;
4460
4461         /* key */
4462         for (; ( p < e ) && ( *p != '=' ); p++ ) {
4463                 if ( !AD_CHAR( *p ) ) {
4464                         return LDAP_INVALID_SYNTAX;
4465                 }
4466         }
4467
4468         if ( *p != '=' ) {
4469                 return LDAP_INVALID_SYNTAX;
4470         }
4471
4472         /* server */
4473         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
4474                 if ( !AD_CHAR( *p ) ) {
4475                         return LDAP_INVALID_SYNTAX;
4476                 }
4477         }
4478
4479         if ( *p != ':' ) {
4480                 return LDAP_INVALID_SYNTAX;
4481         }
4482
4483         /* path */
4484         for ( p++; p < e; p++ ) {
4485                 if ( !SLAP_PRINTABLE( *p ) ) {
4486                         return LDAP_INVALID_SYNTAX;
4487                 }
4488         }
4489
4490         return LDAP_SUCCESS;
4491 }
4492
4493 static int
4494 firstComponentNormalize(
4495         slap_mask_t usage,
4496         Syntax *syntax,
4497         MatchingRule *mr,
4498         struct berval *val,
4499         struct berval *normalized,
4500         void *ctx )
4501 {
4502         int rc;
4503         struct berval comp;
4504         ber_len_t len;
4505
4506         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
4507                 ber_dupbv_x( normalized, val, ctx );
4508                 return LDAP_SUCCESS;
4509         }
4510
4511         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4512
4513         if( val->bv_val[0] != '(' /*')'*/ &&
4514                 val->bv_val[0] != '{' /*'}'*/ )
4515         {
4516                 return LDAP_INVALID_SYNTAX;
4517         }
4518
4519         /* trim leading white space */
4520         for( len=1;
4521                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
4522                 len++ )
4523         {
4524                 /* empty */
4525         }
4526
4527         /* grab next word */
4528         comp.bv_val = &val->bv_val[len];
4529         len = val->bv_len - len;
4530         for( comp.bv_len = 0;
4531                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
4532                 comp.bv_len++ )
4533         {
4534                 /* empty */
4535         }
4536
4537         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
4538                 rc = numericoidValidate( NULL, &comp );
4539         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
4540                 rc = integerValidate( NULL, &comp );
4541         } else {
4542                 rc = LDAP_INVALID_SYNTAX;
4543         }
4544         
4545
4546         if( rc == LDAP_SUCCESS ) {
4547                 ber_dupbv_x( normalized, &comp, ctx );
4548         }
4549
4550         return rc;
4551 }
4552
4553 static char *country_gen_syn[] = {
4554         "1.3.6.1.4.1.1466.115.121.1.15",
4555         "1.3.6.1.4.1.1466.115.121.1.26",
4556         "1.3.6.1.4.1.1466.115.121.1.44",
4557         NULL
4558 };
4559
4560 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
4561 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
4562
4563 static slap_syntax_defs_rec syntax_defs[] = {
4564         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
4565                 X_BINARY X_NOT_H_R ")",
4566                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
4567         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
4568                 0, NULL, NULL, NULL},
4569         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
4570                 0, NULL, NULL, NULL},
4571         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
4572                 X_NOT_H_R ")",
4573                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4574         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
4575                 X_NOT_H_R ")",
4576                 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4577         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
4578                 0, NULL, bitStringValidate, NULL },
4579         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
4580                 0, NULL, booleanValidate, NULL},
4581         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
4582                 X_BINARY X_NOT_H_R ")",
4583                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4584                 NULL, certificateValidate, NULL},
4585         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
4586                 X_BINARY X_NOT_H_R ")",
4587                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4588                 NULL, certificateListValidate, NULL},
4589         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4590                 X_BINARY X_NOT_H_R ")",
4591                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4592                 NULL, sequenceValidate, NULL},
4593 #if 0   /* need to go __after__ printableString */
4594         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4595                 0, "1.3.6.1.4.1.1466.115.121.1.44",
4596                 countryStringValidate, NULL},
4597 #endif
4598         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4599                 0, NULL, dnValidate, dnPretty},
4600         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
4601                 0, NULL, rdnValidate, rdnPretty},
4602 #ifdef LDAP_COMP_MATCH
4603         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
4604                 0, NULL, allComponentsValidate, NULL},
4605         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
4606                 0, NULL, componentFilterValidate, NULL},
4607 #endif
4608         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4609                 0, NULL, NULL, NULL},
4610         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4611                 0, NULL, deliveryMethodValidate, NULL},
4612         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4613                 0, NULL, UTF8StringValidate, NULL},
4614         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4615                 0, NULL, NULL, NULL},
4616         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4617                 0, NULL, NULL, NULL},
4618         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4619                 0, NULL, NULL, NULL},
4620         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4621                 0, NULL, NULL, NULL},
4622         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4623                 0, NULL, NULL, NULL},
4624         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4625                 0, NULL, printablesStringValidate, NULL},
4626         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4627                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
4628         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4629                 0, NULL, generalizedTimeValidate, NULL},
4630         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4631                 0, NULL, NULL, NULL},
4632         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4633                 0, NULL, IA5StringValidate, NULL},
4634         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4635                 0, NULL, integerValidate, NULL},
4636         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4637                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4638         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4639                 0, NULL, NULL, NULL},
4640         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4641                 0, NULL, NULL, NULL},
4642         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4643                 0, NULL, NULL, NULL},
4644         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4645                 0, NULL, NULL, NULL},
4646         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4647                 0, NULL, NULL, NULL},
4648         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4649                 0, NULL, nameUIDValidate, nameUIDPretty },
4650         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4651                 0, NULL, NULL, NULL},
4652         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4653                 0, NULL, numericStringValidate, NULL},
4654         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4655                 0, NULL, NULL, NULL},
4656         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4657                 0, NULL, numericoidValidate, NULL},
4658         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4659                 0, NULL, IA5StringValidate, NULL},
4660         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4661                 0, NULL, blobValidate, NULL},
4662         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4663                 0, NULL, UTF8StringValidate, NULL},
4664         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4665                 0, NULL, NULL, NULL},
4666         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4667                 0, NULL, NULL, NULL},
4668         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4669                 0, NULL, printableStringValidate, NULL},
4670         /* moved here because now depends on Directory String, IA5 String 
4671          * and Printable String */
4672         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4673                 0, country_gen_syn, countryStringValidate, NULL},
4674         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
4675 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
4676                 0, NULL, subtreeSpecificationValidate, NULL},
4677         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4678                 X_BINARY X_NOT_H_R ")",
4679                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4680         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4681                 0, NULL, printableStringValidate, NULL},
4682         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4683                 0, NULL, NULL, NULL},
4684         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4685                 0, NULL, printablesStringValidate, NULL},
4686 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4687         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4688                 0, NULL, utcTimeValidate, NULL},
4689 #endif
4690         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4691                 0, NULL, NULL, NULL},
4692         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4693                 0, NULL, NULL, NULL},
4694         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4695                 0, NULL, NULL, NULL},
4696         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4697                 0, NULL, NULL, NULL},
4698         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4699                 0, NULL, NULL, NULL},
4700
4701         /* RFC 2307 NIS Syntaxes */
4702         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
4703                 0, NULL, nisNetgroupTripleValidate, NULL},
4704         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
4705                 0, NULL, bootParameterValidate, NULL},
4706
4707         /* draft-zeilenga-ldap-x509 */
4708         {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
4709                 SLAP_SYNTAX_HIDE, NULL,
4710                 serialNumberAndIssuerValidate,
4711                 serialNumberAndIssuerPretty},
4712         {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
4713                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4714         {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
4715                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4716         {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
4717                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4718         {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
4719                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4720         {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
4721                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4722         {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
4723                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4724
4725 #ifdef SLAPD_AUTHPASSWD
4726         /* needs updating */
4727         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4728                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4729 #endif
4730
4731         {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
4732                 0, NULL, UUIDValidate, UUIDPretty},
4733
4734         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
4735                 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
4736
4737         {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
4738                 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
4739
4740         /* OpenLDAP Void Syntax */
4741         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4742                 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
4743
4744         /* FIXME: OID is unused, but not registered yet */
4745         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
4746                 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
4747
4748         {NULL, 0, NULL, NULL, NULL}
4749 };
4750
4751 char *csnSIDMatchSyntaxes[] = {
4752         "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
4753         NULL
4754 };
4755 char *certificateExactMatchSyntaxes[] = {
4756         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4757         NULL
4758 };
4759 #ifdef LDAP_COMP_MATCH
4760 char *componentFilterMatchSyntaxes[] = {
4761         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4762         NULL
4763 };
4764 #endif
4765 char *directoryStringSyntaxes[] = {
4766         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
4767         NULL
4768 };
4769 char *integerFirstComponentMatchSyntaxes[] = {
4770         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
4771         "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
4772         NULL
4773 };
4774 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
4775         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
4776         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
4777         "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
4778         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
4779         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
4780         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
4781         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
4782         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
4783         NULL
4784 };
4785
4786 /*
4787  * Other matching rules in X.520 that we do not use (yet):
4788  *
4789  * 2.5.13.25    uTCTimeMatch
4790  * 2.5.13.26    uTCTimeOrderingMatch
4791  * 2.5.13.31*   directoryStringFirstComponentMatch
4792  * 2.5.13.32*   wordMatch
4793  * 2.5.13.33*   keywordMatch
4794  * 2.5.13.36+   certificatePairExactMatch
4795  * 2.5.13.37+   certificatePairMatch
4796  * 2.5.13.38+   certificateListExactMatch
4797  * 2.5.13.39+   certificateListMatch
4798  * 2.5.13.40+   algorithmIdentifierMatch
4799  * 2.5.13.41*   storedPrefixMatch
4800  * 2.5.13.42    attributeCertificateMatch
4801  * 2.5.13.43    readerAndKeyIDMatch
4802  * 2.5.13.44    attributeIntegrityMatch
4803  *
4804  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
4805  * (+) described in draft-zeilenga-ldap-x509
4806  */
4807 static slap_mrule_defs_rec mrule_defs[] = {
4808         /*
4809          * EQUALITY matching rules must be listed after associated APPROX
4810          * matching rules.  So, we list all APPROX matching rules first.
4811          */
4812         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4813                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4814                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4815                 NULL, NULL, directoryStringApproxMatch,
4816                 directoryStringApproxIndexer, directoryStringApproxFilter,
4817                 NULL},
4818
4819         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4820                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4821                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4822                 NULL, NULL, IA5StringApproxMatch,
4823                 IA5StringApproxIndexer, IA5StringApproxFilter,
4824                 NULL},
4825
4826         /*
4827          * Other matching rules
4828          */
4829         
4830         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4831                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4832                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4833                 NULL, NULL, octetStringMatch,
4834                 octetStringIndexer, octetStringFilter,
4835                 NULL },
4836
4837         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4838                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4839                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4840                 NULL, dnNormalize, dnMatch,
4841                 octetStringIndexer, octetStringFilter,
4842                 NULL },
4843
4844         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
4845                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4846                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4847                 NULL, dnNormalize, dnRelativeMatch,
4848                 NULL, NULL,
4849                 NULL },
4850
4851         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
4852                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4853                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4854                 NULL, dnNormalize, dnRelativeMatch,
4855                 NULL, NULL,
4856                 NULL },
4857
4858         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
4859                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4860                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4861                 NULL, dnNormalize, dnRelativeMatch,
4862                 NULL, NULL,
4863                 NULL },
4864
4865         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
4866                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4867                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4868                 NULL, dnNormalize, dnRelativeMatch,
4869                 NULL, NULL,
4870                 NULL },
4871
4872         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
4873                 "SYNTAX 1.2.36.79672281.1.5.0 )",
4874                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4875                 NULL, rdnNormalize, rdnMatch,
4876                 octetStringIndexer, octetStringFilter,
4877                 NULL },
4878
4879 #ifdef LDAP_COMP_MATCH
4880         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
4881                 "SYNTAX 1.2.36.79672281.1.5.2 )",
4882                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
4883                 NULL, NULL , componentFilterMatch,
4884                 octetStringIndexer, octetStringFilter,
4885                 NULL },
4886
4887         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
4888                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4889                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4890                 NULL, NULL , allComponentsMatch,
4891                 octetStringIndexer, octetStringFilter,
4892                 NULL },
4893
4894         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
4895                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4896                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4897                 NULL, NULL , directoryComponentsMatch,
4898                 octetStringIndexer, octetStringFilter,
4899                 NULL },
4900 #endif
4901
4902         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4903                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4904                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4905                 NULL, UTF8StringNormalize, octetStringMatch,
4906                 octetStringIndexer, octetStringFilter,
4907                 directoryStringApproxMatchOID },
4908
4909         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4910                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4911                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4912                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4913                 NULL, NULL,
4914                 "caseIgnoreMatch" },
4915
4916         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4917                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4918                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4919                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4920                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4921                 "caseIgnoreMatch" },
4922
4923         {"( 2.5.13.5 NAME 'caseExactMatch' "
4924                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4925                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4926                 NULL, UTF8StringNormalize, octetStringMatch,
4927                 octetStringIndexer, octetStringFilter,
4928                 directoryStringApproxMatchOID },
4929
4930         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4931                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4932                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4933                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4934                 NULL, NULL,
4935                 "caseExactMatch" },
4936
4937         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4938                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4939                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4940                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4941                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4942                 "caseExactMatch" },
4943
4944         {"( 2.5.13.8 NAME 'numericStringMatch' "
4945                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4946                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4947                 NULL, numericStringNormalize, octetStringMatch,
4948                 octetStringIndexer, octetStringFilter,
4949                 NULL },
4950
4951         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
4952                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4953                 SLAP_MR_ORDERING, NULL,
4954                 NULL, numericStringNormalize, octetStringOrderingMatch,
4955                 NULL, NULL,
4956                 "numericStringMatch" },
4957
4958         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4959                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4960                 SLAP_MR_SUBSTR, NULL,
4961                 NULL, numericStringNormalize, octetStringSubstringsMatch,
4962                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4963                 "numericStringMatch" },
4964
4965         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4966                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4967                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4968                 NULL, NULL, NULL, NULL, NULL, NULL },
4969
4970         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4971                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4972                 SLAP_MR_SUBSTR, NULL,
4973                 NULL, NULL, NULL, NULL, NULL,
4974                 "caseIgnoreListMatch" },
4975
4976         {"( 2.5.13.13 NAME 'booleanMatch' "
4977                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
4978                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4979                 NULL, NULL, booleanMatch,
4980                 octetStringIndexer, octetStringFilter,
4981                 NULL },
4982
4983         {"( 2.5.13.14 NAME 'integerMatch' "
4984                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4985                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4986                 NULL, NULL, integerMatch,
4987                 octetStringIndexer, octetStringFilter,
4988                 NULL },
4989
4990         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
4991                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4992                 SLAP_MR_ORDERING, NULL,
4993                 NULL, NULL, integerMatch,
4994                 NULL, NULL,
4995                 "integerMatch" },
4996
4997         {"( 2.5.13.16 NAME 'bitStringMatch' "
4998                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
4999                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5000                 NULL, NULL, octetStringMatch,
5001                 octetStringIndexer, octetStringFilter,
5002                 NULL },
5003
5004         {"( 2.5.13.17 NAME 'octetStringMatch' "
5005                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5006                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5007                 NULL, NULL, octetStringMatch,
5008                 octetStringIndexer, octetStringFilter,
5009                 NULL },
5010
5011         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
5012                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5013                 SLAP_MR_ORDERING, NULL,
5014                 NULL, NULL, octetStringOrderingMatch,
5015                 NULL, NULL,
5016                 "octetStringMatch" },
5017
5018         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
5019                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5020                 SLAP_MR_SUBSTR, NULL,
5021                 NULL, NULL, octetStringSubstringsMatch,
5022                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5023                 "octetStringMatch" },
5024
5025         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
5026                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
5027                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5028                 NULL,
5029                 telephoneNumberNormalize, octetStringMatch,
5030                 octetStringIndexer, octetStringFilter,
5031                 NULL },
5032
5033         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
5034                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
5035                 SLAP_MR_SUBSTR, NULL,
5036                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
5037                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5038                 "telephoneNumberMatch" },
5039
5040         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
5041                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
5042                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5043                 NULL, NULL, NULL, NULL, NULL, NULL },
5044
5045         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
5046                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
5047                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5048                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
5049                 uniqueMemberIndexer, uniqueMemberFilter,
5050                 NULL },
5051
5052         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
5053                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
5054                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5055                 NULL, NULL, NULL, NULL, NULL, NULL },
5056
5057         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
5058                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
5059                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
5060                 NULL, generalizedTimeNormalize, octetStringMatch,
5061                 generalizedTimeIndexer, generalizedTimeFilter,
5062                 NULL },
5063
5064         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
5065                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
5066                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5067                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
5068                 NULL, NULL,
5069                 "generalizedTimeMatch" },
5070
5071         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
5072                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5073                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
5074                         integerFirstComponentMatchSyntaxes,
5075                 NULL, firstComponentNormalize, integerMatch,
5076                 octetStringIndexer, octetStringFilter,
5077                 NULL },
5078
5079         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
5080                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
5081                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
5082                         objectIdentifierFirstComponentMatchSyntaxes,
5083                 NULL, firstComponentNormalize, octetStringMatch,
5084                 octetStringIndexer, octetStringFilter,
5085                 NULL },
5086
5087         {"( 2.5.13.34 NAME 'certificateExactMatch' "
5088                 "SYNTAX 1.3.6.1.1.15.1 )",
5089                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
5090                 NULL, certificateExactNormalize, octetStringMatch,
5091                 octetStringIndexer, octetStringFilter,
5092                 NULL },
5093
5094         {"( 2.5.13.35 NAME 'certificateMatch' "
5095                 "SYNTAX 1.3.6.1.1.15.2 )",
5096                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5097                 NULL, NULL, NULL, NULL, NULL,
5098                 NULL },
5099
5100         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
5101                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5102                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5103                 NULL, IA5StringNormalize, octetStringMatch,
5104                 octetStringIndexer, octetStringFilter,
5105                 IA5StringApproxMatchOID },
5106
5107         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
5108                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5109                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5110                 NULL, IA5StringNormalize, octetStringMatch,
5111                 octetStringIndexer, octetStringFilter,
5112                 IA5StringApproxMatchOID },
5113
5114         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
5115                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5116                 SLAP_MR_SUBSTR, NULL,
5117                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
5118                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5119                 "caseIgnoreIA5Match" },
5120
5121         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
5122                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5123                 SLAP_MR_SUBSTR, NULL,
5124                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
5125                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5126                 "caseExactIA5Match" },
5127
5128 #ifdef SLAPD_AUTHPASSWD
5129         /* needs updating */
5130         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
5131                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5132                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5133                 NULL, NULL, authPasswordMatch,
5134                 NULL, NULL,
5135                 NULL},
5136 #endif
5137
5138         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
5139                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5140                 SLAP_MR_EXT, NULL,
5141                 NULL, NULL, integerBitAndMatch,
5142                 NULL, NULL,
5143                 "integerMatch" },
5144
5145         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
5146                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5147                 SLAP_MR_EXT, NULL,
5148                 NULL, NULL, integerBitOrMatch,
5149                 NULL, NULL,
5150                 "integerMatch" },
5151
5152         {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
5153                 "SYNTAX 1.3.6.1.1.16.1 )",
5154                 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
5155                 NULL, UUIDNormalize, octetStringMatch,
5156                 octetStringIndexer, octetStringFilter,
5157                 NULL},
5158
5159         {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
5160                 "SYNTAX 1.3.6.1.1.16.1 )",
5161                 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
5162                 NULL, UUIDNormalize, octetStringOrderingMatch,
5163                 octetStringIndexer, octetStringFilter,
5164                 "UUIDMatch"},
5165
5166         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
5167                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5168                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
5169                 NULL, csnNormalize, csnMatch,
5170                 csnIndexer, csnFilter,
5171                 NULL},
5172
5173         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
5174                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5175                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5176                 NULL, NULL, csnOrderingMatch,
5177                 NULL, NULL,
5178                 "CSNMatch" },
5179
5180         {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
5181                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
5182                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
5183                 NULL, csnSidNormalize, octetStringMatch,
5184                 octetStringIndexer, octetStringFilter,
5185                 NULL },
5186
5187         /* FIXME: OID is unused, but not registered yet */
5188         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
5189                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
5190                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5191                 NULL, authzNormalize, authzMatch,
5192                 NULL, NULL,
5193                 NULL},
5194
5195         {NULL, SLAP_MR_NONE, NULL,
5196                 NULL, NULL, NULL, NULL, NULL,
5197                 NULL }
5198 };
5199
5200 int
5201 slap_schema_init( void )
5202 {
5203         int             res;
5204         int             i;
5205
5206         /* we should only be called once (from main) */
5207         assert( schema_init_done == 0 );
5208
5209         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
5210                 res = register_syntax( &syntax_defs[i] );
5211
5212                 if ( res ) {
5213                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
5214                                  syntax_defs[i].sd_desc );
5215                         return LDAP_OTHER;
5216                 }
5217         }
5218
5219         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
5220                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
5221                         mrule_defs[i].mrd_compat_syntaxes == NULL )
5222                 {
5223                         fprintf( stderr,
5224                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
5225                                  mrule_defs[i].mrd_desc );
5226                         continue;
5227                 }
5228
5229                 res = register_matching_rule( &mrule_defs[i] );
5230
5231                 if ( res ) {
5232                         fprintf( stderr,
5233                                 "slap_schema_init: Error registering matching rule %s\n",
5234                                  mrule_defs[i].mrd_desc );
5235                         return LDAP_OTHER;
5236                 }
5237         }
5238
5239         res = slap_schema_load();
5240         schema_init_done = 1;
5241         return res;
5242 }
5243
5244 void
5245 schema_destroy( void )
5246 {
5247         oidm_destroy();
5248         oc_destroy();
5249         at_destroy();
5250         mr_destroy();
5251         mru_destroy();
5252         syn_destroy();
5253
5254         if( schema_init_done ) {
5255                 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
5256                 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
5257         }
5258 }