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