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