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