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