]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
41250c019014263ac9a55971d17ae32d78285b57
[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                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2603                         x.bv_val++; x.bv_len--;
2604
2605                         is->bv_val = x.bv_val;
2606                         is->bv_len = 0;
2607
2608                         for( ; is->bv_len < x.bv_len; ) {
2609                                 if ( is->bv_val[is->bv_len] != '"' ) {
2610                                         is->bv_len++;
2611                                         continue;
2612                                 }
2613                                 if ( is->bv_val[is->bv_len+1] == '"' ) {
2614                                         /* double dquote */
2615                                         is->bv_len+=2;
2616                                         continue;
2617                                 }
2618                                 break;
2619                         }
2620                         x.bv_val += is->bv_len+1;
2621                         x.bv_len -= is->bv_len+1;
2622
2623                         if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2624                                 return LDAP_INVALID_SYNTAX;
2625                         }
2626
2627                         haveissuer++;
2628
2629                 } else if( strncasecmp( x.bv_val, "serialNumber",
2630                         STRLENOF("serialNumber")) == 0 )
2631                 {
2632                         /* parse serialNumber */
2633                         int neg=0;
2634                         x.bv_val += STRLENOF("serialNumber");
2635                         x.bv_len -= STRLENOF("serialNumber");
2636
2637                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2638                         x.bv_val++; x.bv_len--;
2639
2640                         /* eat leading spaces */
2641                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2642                                 /* empty */;
2643                         }
2644                         
2645                         sn->bv_val = x.bv_val;
2646                         sn->bv_len = 0;
2647
2648                         if( sn->bv_val[0] == '-' ) {
2649                                 neg++;
2650                                 sn->bv_len++;
2651                         }
2652
2653                         if ( sn->bv_val[0] == '0' && ( sn->bv_val[1] == 'x' ||
2654                                 sn->bv_val[1] == 'X' )) {
2655                                 is_hex = 1;
2656                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2657                                         if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2658                                 }
2659                         } else if ( sn->bv_val[0] == '\'' ) {
2660                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2661                                         if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2662                                 }
2663                                 if ( sn->bv_val[sn->bv_len] == '\'' &&
2664                                         sn->bv_val[sn->bv_len+1] == 'H' )
2665                                         is_hex = 1;
2666                                 else
2667                                         return LDAP_INVALID_SYNTAX;
2668                                 sn->bv_len += 2;
2669                         } else {
2670                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2671                                         if ( !ASCII_DIGIT( sn->bv_val[sn->bv_len] )) break;
2672                                 }
2673                         }
2674
2675                         if (!( sn->bv_len > neg )) return LDAP_INVALID_SYNTAX;
2676                         if (( sn->bv_len > 1+neg ) && ( sn->bv_val[neg] == '0' )) {
2677                                 return LDAP_INVALID_SYNTAX;
2678                         }
2679
2680                         x.bv_val += sn->bv_len; x.bv_len -= sn->bv_len;
2681
2682                         if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2683                                 return LDAP_INVALID_SYNTAX;
2684                         }
2685
2686                         havesn++;
2687
2688                 } else return LDAP_INVALID_SYNTAX;
2689
2690                 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2691                 x.bv_val++; x.bv_len--;
2692
2693                 /* eat spaces */
2694                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2695                         /* empty */;
2696                 }
2697
2698                 /* should be at remaining NamedValue */
2699                 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2700                         STRLENOF("issuer" )) == 0 ))
2701                 {
2702                         /* parse issuer */
2703                         x.bv_val += STRLENOF("issuer");
2704                         x.bv_len -= STRLENOF("issuer");
2705
2706                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2707                         x.bv_val++; x.bv_len--;
2708
2709                         /* eat leading spaces */
2710                         for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2711                                  /* empty */;
2712                         }
2713                         
2714                         if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2715                         x.bv_val++; x.bv_len--;
2716
2717                         is->bv_val = x.bv_val;
2718                         is->bv_len = 0;
2719
2720                         for( ; is->bv_len < x.bv_len; ) {
2721                                 if ( is->bv_val[is->bv_len] != '"' ) {
2722                                         is->bv_len++;
2723                                         continue;
2724                                 }
2725                                 if ( is->bv_val[is->bv_len+1] == '"' ) {
2726                                         /* double dquote */
2727                                         is->bv_len+=2;
2728                                         continue;
2729                                 }
2730                                 break;
2731                         }
2732                         x.bv_val += is->bv_len+1;
2733                         x.bv_len -= is->bv_len+1;
2734
2735                 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2736                         STRLENOF("serialNumber")) == 0 ))
2737                 {
2738                         /* parse serialNumber */
2739                         int neg=0;
2740                         x.bv_val += STRLENOF("serialNumber");
2741                         x.bv_len -= STRLENOF("serialNumber");
2742
2743                         if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2744                         x.bv_val++; x.bv_len--;
2745
2746                         /* eat leading spaces */
2747                         for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2748                                 /* empty */;
2749                         }
2750                         
2751                         sn->bv_val = x.bv_val;
2752                         sn->bv_len = 0;
2753
2754                         if( sn->bv_val[0] == '-' ) {
2755                                 neg++;
2756                                 sn->bv_len++;
2757                         }
2758
2759                         if ( sn->bv_val[0] == '0' && ( sn->bv_val[1] == 'x' ||
2760                                 sn->bv_val[1] == 'X' )) {
2761                                 is_hex = 1;
2762                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2763                                         if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2764                                 }
2765                         } else if ( sn->bv_val[0] == '\'' ) {
2766                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2767                                         if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2768                                 }
2769                                 if ( sn->bv_val[sn->bv_len] == '\'' &&
2770                                         sn->bv_val[sn->bv_len+1] == 'H' )
2771                                         is_hex = 1;
2772                                 else
2773                                         return LDAP_INVALID_SYNTAX;
2774                                 sn->bv_len += 2;
2775                         } else {
2776                                 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2777                                         if ( !ASCII_DIGIT( sn->bv_val[sn->bv_len] )) break;
2778                                 }
2779                         }
2780
2781                         if (!( sn->bv_len > neg )) return LDAP_INVALID_SYNTAX;
2782                         if (( sn->bv_len > 1+neg ) && ( sn->bv_val[neg] == '0' )) {
2783                                 return LDAP_INVALID_SYNTAX;
2784                         }
2785
2786                         x.bv_val += sn->bv_len;
2787                         x.bv_len -= sn->bv_len;
2788
2789                 } else return LDAP_INVALID_SYNTAX;
2790
2791                 /* eat trailing spaces */
2792                 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2793                         /* empty */;
2794                 }
2795
2796                 /* should have no characters left... */
2797                 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
2798
2799                 ber_dupbv_x( &ni, is, ctx );
2800                 *is = ni;
2801
2802                 /* need to handle double dquotes here */
2803         }
2804         return 0;
2805 }
2806         
2807 static int
2808 serialNumberAndIssuerValidate(
2809         Syntax *syntax,
2810         struct berval *in )
2811 {
2812         int rc;
2813         struct berval sn, i;
2814
2815         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
2816                 in->bv_val, 0, 0 );
2817
2818         rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
2819         if ( rc )
2820                 return rc;
2821
2822         /* validate DN -- doesn't handle double dquote */ 
2823         rc = dnValidate( NULL, &i );
2824         if( rc )
2825                 rc = LDAP_INVALID_SYNTAX;
2826
2827         if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
2828                 slap_sl_free( i.bv_val, NULL );
2829         }
2830
2831         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: OKAY\n",
2832                 0, 0, 0 );
2833         return rc;
2834 }
2835
2836 int
2837 serialNumberAndIssuerPretty(
2838         Syntax *syntax,
2839         struct berval *in,
2840         struct berval *out,
2841         void *ctx )
2842 {
2843         int n, rc;
2844         struct berval sn, i, ni;
2845
2846         assert( in != NULL );
2847         assert( out != NULL );
2848
2849         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
2850                 in->bv_val, 0, 0 );
2851
2852         rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
2853         if ( rc )
2854                 return rc;
2855
2856         rc = dnPretty( syntax, &i, &ni, ctx );
2857
2858         if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
2859                 slap_sl_free( i.bv_val, ctx );
2860         }
2861
2862         if( rc ) return LDAP_INVALID_SYNTAX;
2863
2864         /* make room from sn + "$" */
2865         out->bv_len = STRLENOF("{ serialNumber , issuer \"\" }")
2866                 + sn.bv_len + ni.bv_len;
2867         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2868
2869         if( out->bv_val == NULL ) {
2870                 out->bv_len = 0;
2871                 slap_sl_free( ni.bv_val, ctx );
2872                 return LDAP_OTHER;
2873         }
2874
2875         n = 0;
2876         AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
2877                 STRLENOF("{ serialNumber "));
2878         n = STRLENOF("{ serialNumber ");
2879
2880         AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
2881         n += sn.bv_len;
2882
2883         AC_MEMCPY( &out->bv_val[n], ", issuer \"", STRLENOF(", issuer \""));
2884         n += STRLENOF(", issuer \"");
2885
2886         AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
2887         n += ni.bv_len;
2888
2889         AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF("\" }"));
2890         n += STRLENOF("\" }");
2891
2892         out->bv_val[n] = '\0';
2893
2894         assert( n == out->bv_len );
2895
2896         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
2897                 out->bv_val, 0, 0 );
2898
2899         slap_sl_free( ni.bv_val, ctx );
2900
2901         return LDAP_SUCCESS; 
2902 }
2903
2904 /*
2905  * This routine is called by certificateExactNormalize when
2906  * certificateExactNormalize receives a search string instead of
2907  * a certificate. This routine checks if the search value is valid
2908  * and then returns the normalized value
2909  */
2910 static int
2911 serialNumberAndIssuerNormalize(
2912         slap_mask_t usage,
2913         Syntax *syntax,
2914         MatchingRule *mr,
2915         struct berval *in,
2916         struct berval *out,
2917         void *ctx )
2918 {
2919         struct berval sn, sn2, i, ni;
2920         char sbuf[64], *stmp = sbuf;
2921         int rc;
2922         ber_len_t n;
2923         int is_hex = 0;
2924
2925         assert( in != NULL );
2926         assert( out != NULL );
2927
2928         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
2929                 in->bv_val, 0, 0 );
2930
2931         rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
2932         if ( rc )
2933                 return rc;
2934
2935         rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
2936
2937         if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
2938                 slap_sl_free( i.bv_val, ctx );
2939         }
2940
2941         if( rc ) return LDAP_INVALID_SYNTAX;
2942
2943         /* Convert sn to canonical hex */
2944         if ( sn.bv_len > sizeof( sbuf )) {
2945                 stmp = slap_sl_malloc( sn.bv_len, ctx );
2946         }
2947         sn2.bv_val = stmp;
2948         sn2.bv_len = sn.bv_len;
2949         if ( lutil_str2bin( &sn, &sn2 )) {
2950                 rc = LDAP_INVALID_SYNTAX;
2951                 goto leave;
2952         }
2953
2954         /* make room for sn + "$" */
2955         out->bv_len = STRLENOF( "{ serialNumber , issuer \"\" }" )
2956                 + ( sn2.bv_len * 2 + 3 ) + ni.bv_len;
2957         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2958
2959         if( out->bv_val == NULL ) {
2960                 out->bv_len = 0;
2961                 slap_sl_free( ni.bv_val, ctx );
2962                 rc = LDAP_OTHER;
2963                 goto leave;
2964         }
2965
2966         n = 0;
2967         AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
2968                 STRLENOF( "{ serialNumber " ));
2969         n = STRLENOF( "{ serialNumber " );
2970
2971         AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
2972         {
2973                 int j;
2974                 unsigned char *v = sn2.bv_val;
2975                 out->bv_val[n++] = '\'';
2976                 for ( j = 0; j < sn2.bv_len; j++ ) {
2977                         sprintf( &out->bv_val[n], "%02x", v[j] );
2978                         n += 2;
2979                 }
2980                 out->bv_val[n++] = '\'';
2981                 out->bv_val[n++] = 'H';
2982         }
2983
2984         AC_MEMCPY( &out->bv_val[n], ", issuer \"", STRLENOF( ", issuer \"" ));
2985         n += STRLENOF( ", issuer \"" );
2986
2987         AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
2988         n += ni.bv_len;
2989
2990         AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF( "\" }" ));
2991         n += STRLENOF( "\" }" );
2992
2993         out->bv_val[n] = '\0';
2994
2995         assert( n == out->bv_len );
2996
2997         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
2998                 out->bv_val, 0, 0 );
2999
3000 leave:
3001         if ( stmp != sbuf )
3002                 slap_sl_free( stmp, ctx );
3003         slap_sl_free( ni.bv_val, ctx );
3004
3005         return rc;
3006 }
3007
3008 static int
3009 certificateExactNormalize(
3010         slap_mask_t usage,
3011         Syntax *syntax,
3012         MatchingRule *mr,
3013         struct berval *val,
3014         struct berval *normalized,
3015         void *ctx )
3016 {
3017         BerElementBuffer berbuf;
3018         BerElement *ber = (BerElement *)&berbuf;
3019         ber_tag_t tag;
3020         ber_len_t len;
3021         ber_int_t i;
3022         char serialbuf[64], *serial = serialbuf;
3023         ber_len_t seriallen;
3024         struct berval issuer_dn = BER_BVNULL, bvdn;
3025         unsigned char *p;
3026         int rc = LDAP_INVALID_SYNTAX;
3027
3028         if( BER_BVISEMPTY( val ) ) goto done;
3029
3030         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3031                 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
3032         }
3033
3034         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3035
3036         ber_init2( ber, val, LBER_USE_DER );
3037         tag = ber_skip_tag( ber, &len );        /* Signed Sequence */
3038         tag = ber_skip_tag( ber, &len );        /* Sequence */
3039         tag = ber_peek_tag( ber, &len );        /* Optional version? */
3040         if ( tag == SLAP_X509_OPT_C_VERSION ) {
3041                 tag = ber_skip_tag( ber, &len );
3042                 tag = ber_get_int( ber, &i );   /* version */
3043         }
3044
3045         /* NOTE: move the test here from certificateValidate,
3046          * so that we can validate certs with serial longer
3047          * than sizeof(ber_int_t) */
3048         tag = ber_peek_tag( ber, &len );        /* serial */
3049
3050         /* Use hex format. '123456789abcdef'H
3051          */
3052         {
3053                 unsigned char *ptr;
3054                 char *sptr;
3055                 
3056                 tag = ber_skip_tag( ber, &len );
3057                 ptr = (unsigned char *)ber->ber_ptr;
3058                 ber_skip_data( ber, len );
3059
3060                 /* Check for minimal encodings */
3061                 if ( len > 1 ) {
3062                         if ( ptr[0] & 0x80 ) {
3063                                 if (( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ))
3064                                         return LDAP_INVALID_SYNTAX;
3065                         } else if ( ptr[0] == 0 ) {
3066                                 if (!( ptr[1] & 0x80 ))
3067                                         return LDAP_INVALID_SYNTAX;
3068                         }
3069                 }
3070
3071                 seriallen = len * 2 + 4;        /* quotes, H, NUL */
3072                 if ( seriallen > sizeof( serialbuf ))
3073                         serial = slap_sl_malloc( seriallen, ctx );
3074                 sptr = serial;
3075                 *sptr++ = '\'';
3076                 for ( i = 0; i<len; i++ ) {
3077                         sprintf( sptr, "%02x", ptr[i] );
3078                         sptr += 2;
3079                 }
3080                 *sptr++ = '\'';
3081                 *sptr++ = 'H';
3082                 seriallen--;
3083         }
3084         tag = ber_skip_tag( ber, &len );        /* SignatureAlg */
3085         ber_skip_data( ber, len );
3086         tag = ber_peek_tag( ber, &len );        /* IssuerDN */
3087         len = ber_ptrlen( ber );
3088         bvdn.bv_val = val->bv_val + len;
3089         bvdn.bv_len = val->bv_len - len;
3090
3091         rc = dnX509normalize( &bvdn, &issuer_dn );
3092         if( rc != LDAP_SUCCESS ) goto done;
3093
3094         normalized->bv_len = STRLENOF( "{ serialNumber , issuer \"\" }" )
3095                 + seriallen + issuer_dn.bv_len;
3096         normalized->bv_val = ch_malloc(normalized->bv_len+1);
3097
3098         p = (unsigned char *)normalized->bv_val;
3099
3100         AC_MEMCPY(p, "{ serialNumber ", STRLENOF( "{ serialNumber " ));
3101         p += STRLENOF( "{ serialNumber " );
3102
3103         AC_MEMCPY(p, serial, seriallen);
3104         p += seriallen;
3105
3106         AC_MEMCPY(p, ", issuer \"", STRLENOF( ", issuer \"" ));
3107         p += STRLENOF( ", issuer \"" );
3108
3109         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
3110         p += issuer_dn.bv_len;
3111
3112         AC_MEMCPY(p, "\" }", STRLENOF( "\" }" ));
3113         p += STRLENOF( "\" }" );
3114
3115         *p = '\0';
3116
3117         Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
3118                 normalized->bv_val, NULL, NULL );
3119
3120         rc = LDAP_SUCCESS;
3121
3122 done:
3123         if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3124         if ( serial != serialbuf ) ber_memfree_x( serial, ctx );
3125
3126         return rc;
3127 }
3128
3129 static int
3130 hexValidate(
3131         Syntax *syntax,
3132         struct berval *in )
3133 {
3134         int     i;
3135
3136         assert( in != NULL );
3137         assert( !BER_BVISNULL( in ) );
3138
3139         for ( i = 0; i < in->bv_len; i++ ) {
3140                 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
3141                         return LDAP_INVALID_SYNTAX;
3142                 }
3143         }
3144
3145         return LDAP_SUCCESS;
3146 }
3147
3148 /* Normalize a SID as used inside a CSN:
3149  * three-digit numeric string */
3150 static int
3151 hexNormalize(
3152         slap_mask_t usage,
3153         Syntax *syntax,
3154         MatchingRule *mr,
3155         struct berval *val,
3156         struct berval *normalized,
3157         void *ctx )
3158 {
3159         int     i;
3160
3161         assert( val != NULL );
3162         assert( normalized != NULL );
3163
3164         ber_dupbv_x( normalized, val, ctx );
3165
3166         for ( i = 0; i < normalized->bv_len; i++ ) {
3167                 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
3168                         ber_memfree_x( normalized->bv_val, ctx );
3169                         BER_BVZERO( normalized );
3170                         return LDAP_INVALID_SYNTAX;
3171                 }
3172
3173                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3174         }
3175
3176         return LDAP_SUCCESS;
3177 }
3178
3179 static int
3180 sidValidate (
3181         Syntax *syntax,
3182         struct berval *in )
3183 {
3184         assert( in != NULL );
3185         assert( !BER_BVISNULL( in ) );
3186
3187         if ( in->bv_len != 3 ) {
3188                 return LDAP_INVALID_SYNTAX;
3189         }
3190
3191         return hexValidate( NULL, in );
3192 }
3193
3194 /* Normalize a SID as used inside a CSN:
3195  * three-digit numeric string */
3196 static int
3197 sidNormalize(
3198         slap_mask_t usage,
3199         Syntax *syntax,
3200         MatchingRule *mr,
3201         struct berval *val,
3202         struct berval *normalized,
3203         void *ctx )
3204 {
3205         if ( val->bv_len != 3 ) {
3206                 return LDAP_INVALID_SYNTAX;
3207         }
3208
3209         return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
3210 }
3211
3212 static int
3213 sidPretty(
3214         Syntax *syntax,
3215         struct berval *val,
3216         struct berval *out,
3217         void *ctx )
3218 {
3219         return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3220 }
3221
3222 /* Normalize a SID as used inside a CSN, either as-is
3223  * (assertion value) or extracted from the CSN
3224  * (attribute value) */
3225 static int
3226 csnSidNormalize(
3227         slap_mask_t usage,
3228         Syntax *syntax,
3229         MatchingRule *mr,
3230         struct berval *val,
3231         struct berval *normalized,
3232         void *ctx )
3233 {
3234         struct berval   bv;
3235         char            *ptr,
3236                         buf[ 4 ];
3237
3238
3239         if ( BER_BVISEMPTY( val ) ) {
3240                 return LDAP_INVALID_SYNTAX;
3241         }
3242
3243         if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3244                 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
3245         }
3246
3247         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3248
3249         ptr = ber_bvchr( val, '#' );
3250         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3251                 return LDAP_INVALID_SYNTAX;
3252         }
3253
3254         bv.bv_val = ptr + 1;
3255         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3256
3257         ptr = ber_bvchr( &bv, '#' );
3258         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3259                 return LDAP_INVALID_SYNTAX;
3260         }
3261
3262         bv.bv_val = ptr + 1;
3263         bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3264                 
3265         ptr = ber_bvchr( &bv, '#' );
3266         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3267                 return LDAP_INVALID_SYNTAX;
3268         }
3269
3270         bv.bv_len = ptr - bv.bv_val;
3271
3272         if ( bv.bv_len == 2 ) {
3273                 /* OpenLDAP 2.3 SID */
3274                 buf[ 0 ] = '0';
3275                 buf[ 1 ] = bv.bv_val[ 0 ];
3276                 buf[ 2 ] = bv.bv_val[ 1 ];
3277                 buf[ 3 ] = '\0';
3278
3279                 bv.bv_val = buf;
3280                 bv.bv_len = 3;
3281         }
3282
3283         return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
3284 }
3285
3286 static int
3287 csnValidate(
3288         Syntax *syntax,
3289         struct berval *in )
3290 {
3291         struct berval   bv;
3292         char            *ptr;
3293         int             rc;
3294
3295         assert( in != NULL );
3296         assert( !BER_BVISNULL( in ) );
3297
3298         if ( BER_BVISEMPTY( in ) ) {
3299                 return LDAP_INVALID_SYNTAX;
3300         }
3301
3302         bv = *in;
3303
3304         ptr = ber_bvchr( &bv, '#' );
3305         if ( ptr == NULL || ptr - bv.bv_val == bv.bv_len ) {
3306                 return LDAP_INVALID_SYNTAX;
3307         }
3308
3309         bv.bv_len = ptr - bv.bv_val;
3310         if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
3311                 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
3312         {
3313                 return LDAP_INVALID_SYNTAX;
3314         }
3315
3316         rc = generalizedTimeValidate( NULL, &bv );
3317         if ( rc != LDAP_SUCCESS ) {
3318                 return rc;
3319         }
3320
3321         bv.bv_val = ptr + 1;
3322         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3323
3324         ptr = ber_bvchr( &bv, '#' );
3325         if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3326                 return LDAP_INVALID_SYNTAX;
3327         }
3328
3329         bv.bv_len = ptr - bv.bv_val;
3330         if ( bv.bv_len != 6 ) {
3331                 return LDAP_INVALID_SYNTAX;
3332         }
3333
3334         rc = hexValidate( NULL, &bv );
3335         if ( rc != LDAP_SUCCESS ) {
3336                 return rc;
3337         }
3338
3339         bv.bv_val = ptr + 1;
3340         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3341
3342         ptr = ber_bvchr( &bv, '#' );
3343         if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3344                 return LDAP_INVALID_SYNTAX;
3345         }
3346
3347         bv.bv_len = ptr - bv.bv_val;
3348         if ( bv.bv_len == 2 ) {
3349                 /* tolerate old 2-digit replica-id */
3350                 rc = hexValidate( NULL, &bv );
3351
3352         } else {
3353                 rc = sidValidate( NULL, &bv );
3354         }
3355         if ( rc != LDAP_SUCCESS ) {
3356                 return rc;
3357         }
3358
3359         bv.bv_val = ptr + 1;
3360         bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3361
3362         if ( bv.bv_len != 6 ) {
3363                 return LDAP_INVALID_SYNTAX;
3364         }
3365
3366         return hexValidate( NULL, &bv );
3367 }
3368
3369 /* Normalize a CSN in OpenLDAP 2.3 format */
3370 static int
3371 csnNormalize23(
3372         slap_mask_t usage,
3373         Syntax *syntax,
3374         MatchingRule *mr,
3375         struct berval *val,
3376         struct berval *normalized,
3377         void *ctx )
3378 {
3379         struct berval   gt, cnt, sid, mod;
3380         char            *ptr;
3381         int             i;
3382
3383         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3384         assert( !BER_BVISEMPTY( val ) );
3385
3386         gt = *val;
3387
3388         ptr = ber_bvchr( &gt, '#' );
3389         if ( ptr == NULL || ptr - gt.bv_val == gt.bv_len ) {
3390                 return LDAP_INVALID_SYNTAX;
3391         }
3392
3393         gt.bv_len = ptr - gt.bv_val;
3394         assert( gt.bv_len == STRLENOF( "YYYYmmddHHMMSSZ" ) );
3395
3396         cnt.bv_val = ptr + 1;
3397         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3398
3399         ptr = ber_bvchr( &cnt, '#' );
3400         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3401                 return LDAP_INVALID_SYNTAX;
3402         }
3403
3404         cnt.bv_len = ptr - cnt.bv_val;
3405         assert( cnt.bv_len == STRLENOF( "000000" ) );
3406
3407         sid.bv_val = ptr + 1;
3408         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3409                 
3410         ptr = ber_bvchr( &sid, '#' );
3411         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3412                 return LDAP_INVALID_SYNTAX;
3413         }
3414
3415         sid.bv_len = ptr - sid.bv_val;
3416         assert( sid.bv_len == STRLENOF( "00" ) );
3417
3418         mod.bv_val = ptr + 1;
3419         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3420         assert( mod.bv_len == STRLENOF( "000000" ) );
3421
3422         normalized->bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
3423         normalized->bv_val = ber_memalloc_x( normalized->bv_len + 1, ctx );
3424
3425         ptr = normalized->bv_val;
3426         ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
3427         ptr = lutil_strcopy( ptr, ".000000Z#" );
3428         ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
3429         *ptr++ = '#';
3430         *ptr++ = '0';
3431         for ( i = 0; i < sid.bv_len; i++ ) {
3432                 *ptr++ = TOLOWER( sid.bv_val[ i ] );
3433         }
3434         *ptr++ = '#';
3435         for ( i = 0; i < mod.bv_len; i++ ) {
3436                 *ptr++ = TOLOWER( mod.bv_val[ i ] );
3437         }
3438         *ptr = '\0';
3439
3440         assert( ptr - normalized->bv_val == normalized->bv_len );
3441
3442         return LDAP_SUCCESS;
3443 }
3444
3445 /* Normalize a CSN */
3446 static int
3447 csnNormalize(
3448         slap_mask_t usage,
3449         Syntax *syntax,
3450         MatchingRule *mr,
3451         struct berval *val,
3452         struct berval *normalized,
3453         void *ctx )
3454 {
3455         struct berval   cnt, sid, mod;
3456         char            *ptr;
3457         int             i;
3458
3459         assert( val != NULL );
3460         assert( normalized != NULL );
3461
3462         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3463
3464         if ( BER_BVISEMPTY( val ) ) {
3465                 return LDAP_INVALID_SYNTAX;
3466         }
3467
3468         if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
3469                 /* Openldap <= 2.3 */
3470
3471                 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
3472         }
3473
3474         assert( val->bv_len == STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) );
3475
3476         ptr = ber_bvchr( val, '#' );
3477         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3478                 return LDAP_INVALID_SYNTAX;
3479         }
3480
3481         assert( ptr - val->bv_val == STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) );
3482
3483         cnt.bv_val = ptr + 1;
3484         cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3485
3486         ptr = ber_bvchr( &cnt, '#' );
3487         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3488                 return LDAP_INVALID_SYNTAX;
3489         }
3490
3491         assert( ptr - cnt.bv_val == STRLENOF( "000000" ) );
3492
3493         sid.bv_val = ptr + 1;
3494         sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3495                 
3496         ptr = ber_bvchr( &sid, '#' );
3497         if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3498                 return LDAP_INVALID_SYNTAX;
3499         }
3500
3501         sid.bv_len = ptr - sid.bv_val;
3502         assert( sid.bv_len == STRLENOF( "000" ) );
3503
3504         mod.bv_val = ptr + 1;
3505         mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3506
3507         assert( mod.bv_len == STRLENOF( "000000" ) );
3508
3509         ber_dupbv_x( normalized, val, ctx );
3510
3511         for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
3512                 i < normalized->bv_len; i++ )
3513         {
3514                 /* assume it's already validated that's all hex digits */
3515                 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3516         }
3517
3518         return LDAP_SUCCESS;
3519 }
3520
3521 static int
3522 csnPretty(
3523         Syntax *syntax,
3524         struct berval *val,
3525         struct berval *out,
3526         void *ctx )
3527 {
3528         return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3529 }
3530
3531 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
3532 /* slight optimization - does not need the start parameter */
3533 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
3534 enum { start = 0 };
3535 #endif
3536
3537 static int
3538 check_time_syntax (struct berval *val,
3539         int start,
3540         int *parts,
3541         struct berval *fraction)
3542 {
3543         /*
3544          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
3545          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
3546          * GeneralizedTime supports leap seconds, UTCTime does not.
3547          */
3548         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
3549         static const int mdays[2][12] = {
3550                 /* non-leap years */
3551                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
3552                 /* leap years */
3553                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
3554         };
3555         char *p, *e;
3556         int part, c, c1, c2, tzoffset, leapyear = 0;
3557
3558         p = val->bv_val;
3559         e = p + val->bv_len;
3560
3561 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3562         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
3563 #endif
3564         for (part = start; part < 7 && p < e; part++) {
3565                 c1 = *p;
3566                 if (!ASCII_DIGIT(c1)) {
3567                         break;
3568                 }
3569                 p++;
3570                 if (p == e) {
3571                         return LDAP_INVALID_SYNTAX;
3572                 }
3573                 c = *p++;
3574                 if (!ASCII_DIGIT(c)) {
3575                         return LDAP_INVALID_SYNTAX;
3576                 }
3577                 c += c1 * 10 - '0' * 11;
3578                 if ((part | 1) == 3) {
3579                         --c;
3580                         if (c < 0) {
3581                                 return LDAP_INVALID_SYNTAX;
3582                         }
3583                 }
3584                 if (c >= ceiling[part]) {
3585                         if (! (c == 60 && part == 6 && start == 0))
3586                                 return LDAP_INVALID_SYNTAX;
3587                 }
3588                 parts[part] = c;
3589         }
3590         if (part < 5 + start) {
3591                 return LDAP_INVALID_SYNTAX;
3592         }
3593         for (; part < 9; part++) {
3594                 parts[part] = 0;
3595         }
3596
3597         /* leapyear check for the Gregorian calendar (year>1581) */
3598         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
3599                 leapyear = 1;
3600         }
3601
3602         if (parts[3] >= mdays[leapyear][parts[2]]) {
3603                 return LDAP_INVALID_SYNTAX;
3604         }
3605
3606         if (start == 0) {
3607                 fraction->bv_val = p;
3608                 fraction->bv_len = 0;
3609                 if (p < e && (*p == '.' || *p == ',')) {
3610                         char *end_num;
3611                         while (++p < e && ASCII_DIGIT(*p)) {
3612                                 /* EMTPY */;
3613                         }
3614                         if (p - fraction->bv_val == 1) {
3615                                 return LDAP_INVALID_SYNTAX;
3616                         }
3617                         for (end_num = p; end_num[-1] == '0'; --end_num) {
3618                                 /* EMPTY */;
3619                         }
3620                         c = end_num - fraction->bv_val;
3621                         if (c != 1) fraction->bv_len = c;
3622                 }
3623         }
3624
3625         if (p == e) {
3626                 /* no time zone */
3627                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3628         }
3629
3630         tzoffset = *p++;
3631         switch (tzoffset) {
3632         default:
3633                 return LDAP_INVALID_SYNTAX;
3634         case 'Z':
3635                 /* UTC */
3636                 break;
3637         case '+':
3638         case '-':
3639                 for (part = 7; part < 9 && p < e; part++) {
3640                         c1 = *p;
3641                         if (!ASCII_DIGIT(c1)) {
3642                                 break;
3643                         }
3644                         p++;
3645                         if (p == e) {
3646                                 return LDAP_INVALID_SYNTAX;
3647                         }
3648                         c2 = *p++;
3649                         if (!ASCII_DIGIT(c2)) {
3650                                 return LDAP_INVALID_SYNTAX;
3651                         }
3652                         parts[part] = c1 * 10 + c2 - '0' * 11;
3653                         if (parts[part] >= ceiling[part]) {
3654                                 return LDAP_INVALID_SYNTAX;
3655                         }
3656                 }
3657                 if (part < 8 + start) {
3658                         return LDAP_INVALID_SYNTAX;
3659                 }
3660
3661                 if (tzoffset == '-') {
3662                         /* negative offset to UTC, ie west of Greenwich */
3663                         parts[4] += parts[7];
3664                         parts[5] += parts[8];
3665                         /* offset is just hhmm, no seconds */
3666                         for (part = 6; --part >= 0; ) {
3667                                 if (part != 3) {
3668                                         c = ceiling[part];
3669                                 } else {
3670                                         c = mdays[leapyear][parts[2]];
3671                                 }
3672                                 if (parts[part] >= c) {
3673                                         if (part == 0) {
3674                                                 return LDAP_INVALID_SYNTAX;
3675                                         }
3676                                         parts[part] -= c;
3677                                         parts[part - 1]++;
3678                                         continue;
3679                                 } else if (part != 5) {
3680                                         break;
3681                                 }
3682                         }
3683                 } else {
3684                         /* positive offset to UTC, ie east of Greenwich */
3685                         parts[4] -= parts[7];
3686                         parts[5] -= parts[8];
3687                         for (part = 6; --part >= 0; ) {
3688                                 if (parts[part] < 0) {
3689                                         if (part == 0) {
3690                                                 return LDAP_INVALID_SYNTAX;
3691                                         }
3692                                         if (part != 3) {
3693                                                 c = ceiling[part];
3694                                         } else {
3695                                                 /* make first arg to % non-negative */
3696                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
3697                                         }
3698                                         parts[part] += c;
3699                                         parts[part - 1]--;
3700                                         continue;
3701                                 } else if (part != 5) {
3702                                         break;
3703                                 }
3704                         }
3705                 }
3706         }
3707
3708         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3709 }
3710
3711 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3712
3713 #if 0
3714 static int
3715 xutcTimeNormalize(
3716         Syntax *syntax,
3717         struct berval *val,
3718         struct berval *normalized )
3719 {
3720         int parts[9], rc;
3721
3722         rc = check_time_syntax(val, 1, parts, NULL);
3723         if (rc != LDAP_SUCCESS) {
3724                 return rc;
3725         }
3726
3727         normalized->bv_val = ch_malloc( 14 );
3728         if ( normalized->bv_val == NULL ) {
3729                 return LBER_ERROR_MEMORY;
3730         }
3731
3732         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
3733                 parts[1], parts[2] + 1, parts[3] + 1,
3734                 parts[4], parts[5], parts[6] );
3735         normalized->bv_len = 13;
3736
3737         return LDAP_SUCCESS;
3738 }
3739 #endif /* 0 */
3740
3741 static int
3742 utcTimeValidate(
3743         Syntax *syntax,
3744         struct berval *in )
3745 {
3746         int parts[9];
3747         return check_time_syntax(in, 1, parts, NULL);
3748 }
3749
3750 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
3751
3752 static int
3753 generalizedTimeValidate(
3754         Syntax *syntax,
3755         struct berval *in )
3756 {
3757         int parts[9];
3758         struct berval fraction;
3759         return check_time_syntax(in, 0, parts, &fraction);
3760 }
3761
3762 static int
3763 generalizedTimeNormalize(
3764         slap_mask_t usage,
3765         Syntax *syntax,
3766         MatchingRule *mr,
3767         struct berval *val,
3768         struct berval *normalized,
3769         void *ctx )
3770 {
3771         int parts[9], rc;
3772         unsigned int len;
3773         struct berval fraction;
3774
3775         rc = check_time_syntax(val, 0, parts, &fraction);
3776         if (rc != LDAP_SUCCESS) {
3777                 return rc;
3778         }
3779
3780         len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
3781         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
3782         if ( BER_BVISNULL( normalized ) ) {
3783                 return LBER_ERROR_MEMORY;
3784         }
3785
3786         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
3787                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
3788                 parts[4], parts[5], parts[6] );
3789         if ( !BER_BVISEMPTY( &fraction ) ) {
3790                 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
3791                         fraction.bv_val, fraction.bv_len );
3792                 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
3793         }
3794         strcpy( normalized->bv_val + len-1, "Z" );
3795         normalized->bv_len = len;
3796
3797         return LDAP_SUCCESS;
3798 }
3799
3800 static int
3801 generalizedTimeOrderingMatch(
3802         int *matchp,
3803         slap_mask_t flags,
3804         Syntax *syntax,
3805         MatchingRule *mr,
3806         struct berval *value,
3807         void *assertedValue )
3808 {
3809         struct berval *asserted = (struct berval *) assertedValue;
3810         ber_len_t v_len  = value->bv_len;
3811         ber_len_t av_len = asserted->bv_len;
3812
3813         /* ignore trailing 'Z' when comparing */
3814         int match = memcmp( value->bv_val, asserted->bv_val,
3815                 (v_len < av_len ? v_len : av_len) - 1 );
3816         if ( match == 0 ) match = v_len - av_len;
3817
3818         *matchp = match;
3819         return LDAP_SUCCESS;
3820 }
3821
3822 /* Index generation function */
3823 int generalizedTimeIndexer(
3824         slap_mask_t use,
3825         slap_mask_t flags,
3826         Syntax *syntax,
3827         MatchingRule *mr,
3828         struct berval *prefix,
3829         BerVarray values,
3830         BerVarray *keysp,
3831         void *ctx )
3832 {
3833         int i, j;
3834         BerVarray keys;
3835         char tmp[5];
3836         BerValue bvtmp; /* 40 bit index */
3837         struct lutil_tm tm;
3838         struct lutil_timet tt;
3839
3840         bvtmp.bv_len = sizeof(tmp);
3841         bvtmp.bv_val = tmp;
3842         for( i=0; values[i].bv_val != NULL; i++ ) {
3843                 /* just count them */
3844         }
3845
3846         /* we should have at least one value at this point */
3847         assert( i > 0 );
3848
3849         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
3850
3851         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
3852         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
3853                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
3854                 /* Use 40 bits of time for key */
3855                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
3856                         lutil_tm2time( &tm, &tt );
3857                         tmp[0] = tt.tt_gsec & 0xff;
3858                         tmp[4] = tt.tt_sec & 0xff;
3859                         tt.tt_sec >>= 8;
3860                         tmp[3] = tt.tt_sec & 0xff;
3861                         tt.tt_sec >>= 8;
3862                         tmp[2] = tt.tt_sec & 0xff;
3863                         tt.tt_sec >>= 8;
3864                         tmp[1] = tt.tt_sec & 0xff;
3865                         
3866                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
3867                 }
3868         }
3869
3870         keys[j].bv_val = NULL;
3871         keys[j].bv_len = 0;
3872
3873         *keysp = keys;
3874
3875         return LDAP_SUCCESS;
3876 }
3877
3878 /* Index generation function */
3879 int generalizedTimeFilter(
3880         slap_mask_t use,
3881         slap_mask_t flags,
3882         Syntax *syntax,
3883         MatchingRule *mr,
3884         struct berval *prefix,
3885         void * assertedValue,
3886         BerVarray *keysp,
3887         void *ctx )
3888 {
3889         BerVarray keys;
3890         char tmp[5];
3891         BerValue bvtmp; /* 40 bit index */
3892         BerValue *value = (BerValue *) assertedValue;
3893         struct lutil_tm tm;
3894         struct lutil_timet tt;
3895         
3896         bvtmp.bv_len = sizeof(tmp);
3897         bvtmp.bv_val = tmp;
3898         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
3899         /* Use 40 bits of time for key */
3900         if ( value->bv_val && value->bv_len >= 10 &&
3901                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
3902
3903                 lutil_tm2time( &tm, &tt );
3904                 tmp[0] = tt.tt_gsec & 0xff;
3905                 tmp[4] = tt.tt_sec & 0xff;
3906                 tt.tt_sec >>= 8;
3907                 tmp[3] = tt.tt_sec & 0xff;
3908                 tt.tt_sec >>= 8;
3909                 tmp[2] = tt.tt_sec & 0xff;
3910                 tt.tt_sec >>= 8;
3911                 tmp[1] = tt.tt_sec & 0xff;
3912
3913                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
3914                 ber_dupbv_x(keys, &bvtmp, ctx );
3915                 keys[1].bv_val = NULL;
3916                 keys[1].bv_len = 0;
3917         } else {
3918                 keys = NULL;
3919         }
3920
3921         *keysp = keys;
3922
3923         return LDAP_SUCCESS;
3924 }
3925
3926 static int
3927 deliveryMethodValidate(
3928         Syntax *syntax,
3929         struct berval *val )
3930 {
3931 #undef LENOF
3932 #define LENOF(s) (sizeof(s)-1)
3933         struct berval tmp = *val;
3934         /*
3935      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
3936          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
3937          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
3938          */
3939 again:
3940         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3941
3942         switch( tmp.bv_val[0] ) {
3943         case 'a':
3944         case 'A':
3945                 if(( tmp.bv_len >= LENOF("any") ) &&
3946                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
3947                 {
3948                         tmp.bv_len -= LENOF("any");
3949                         tmp.bv_val += LENOF("any");
3950                         break;
3951                 }
3952                 return LDAP_INVALID_SYNTAX;
3953
3954         case 'm':
3955         case 'M':
3956                 if(( tmp.bv_len >= LENOF("mhs") ) &&
3957                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
3958                 {
3959                         tmp.bv_len -= LENOF("mhs");
3960                         tmp.bv_val += LENOF("mhs");
3961                         break;
3962                 }
3963                 return LDAP_INVALID_SYNTAX;
3964
3965         case 'p':
3966         case 'P':
3967                 if(( tmp.bv_len >= LENOF("physical") ) &&
3968                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
3969                 {
3970                         tmp.bv_len -= LENOF("physical");
3971                         tmp.bv_val += LENOF("physical");
3972                         break;
3973                 }
3974                 return LDAP_INVALID_SYNTAX;
3975
3976         case 't':
3977         case 'T': /* telex or teletex or telephone */
3978                 if(( tmp.bv_len >= LENOF("telex") ) &&
3979                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
3980                 {
3981                         tmp.bv_len -= LENOF("telex");
3982                         tmp.bv_val += LENOF("telex");
3983                         break;
3984                 }
3985                 if(( tmp.bv_len >= LENOF("teletex") ) &&
3986                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
3987                 {
3988                         tmp.bv_len -= LENOF("teletex");
3989                         tmp.bv_val += LENOF("teletex");
3990                         break;
3991                 }
3992                 if(( tmp.bv_len >= LENOF("telephone") ) &&
3993                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
3994                 {
3995                         tmp.bv_len -= LENOF("telephone");
3996                         tmp.bv_val += LENOF("telephone");
3997                         break;
3998                 }
3999                 return LDAP_INVALID_SYNTAX;
4000
4001         case 'g':
4002         case 'G': /* g3fax or g4fax */
4003                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
4004                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
4005                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
4006                 {
4007                         tmp.bv_len -= LENOF("g3fax");
4008                         tmp.bv_val += LENOF("g3fax");
4009                         break;
4010                 }
4011                 return LDAP_INVALID_SYNTAX;
4012
4013         case 'i':
4014         case 'I':
4015                 if(( tmp.bv_len >= LENOF("ia5") ) &&
4016                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
4017                 {
4018                         tmp.bv_len -= LENOF("ia5");
4019                         tmp.bv_val += LENOF("ia5");
4020                         break;
4021                 }
4022                 return LDAP_INVALID_SYNTAX;
4023
4024         case 'v':
4025         case 'V':
4026                 if(( tmp.bv_len >= LENOF("videotex") ) &&
4027                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
4028                 {
4029                         tmp.bv_len -= LENOF("videotex");
4030                         tmp.bv_val += LENOF("videotex");
4031                         break;
4032                 }
4033                 return LDAP_INVALID_SYNTAX;
4034
4035         default:
4036                 return LDAP_INVALID_SYNTAX;
4037         }
4038
4039         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
4040
4041         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4042                 tmp.bv_len++;
4043                 tmp.bv_val--;
4044         }
4045         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
4046                 tmp.bv_len++;
4047                 tmp.bv_val--;
4048         } else {
4049                 return LDAP_INVALID_SYNTAX;
4050         }
4051         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4052                 tmp.bv_len++;
4053                 tmp.bv_val--;
4054         }
4055
4056         goto again;
4057 }
4058
4059 static int
4060 nisNetgroupTripleValidate(
4061         Syntax *syntax,
4062         struct berval *val )
4063 {
4064         char *p, *e;
4065         int commas = 0;
4066
4067         if ( BER_BVISEMPTY( val ) ) {
4068                 return LDAP_INVALID_SYNTAX;
4069         }
4070
4071         p = (char *)val->bv_val;
4072         e = p + val->bv_len;
4073
4074         if ( *p != '(' /*')'*/ ) {
4075                 return LDAP_INVALID_SYNTAX;
4076         }
4077
4078         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
4079                 if ( *p == ',' ) {
4080                         commas++;
4081                         if ( commas > 2 ) {
4082                                 return LDAP_INVALID_SYNTAX;
4083                         }
4084
4085                 } else if ( !AD_CHAR( *p ) ) {
4086                         return LDAP_INVALID_SYNTAX;
4087                 }
4088         }
4089
4090         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
4091                 return LDAP_INVALID_SYNTAX;
4092         }
4093
4094         p++;
4095
4096         if (p != e) {
4097                 return LDAP_INVALID_SYNTAX;
4098         }
4099
4100         return LDAP_SUCCESS;
4101 }
4102
4103 static int
4104 bootParameterValidate(
4105         Syntax *syntax,
4106         struct berval *val )
4107 {
4108         char *p, *e;
4109
4110         if ( BER_BVISEMPTY( val ) ) {
4111                 return LDAP_INVALID_SYNTAX;
4112         }
4113
4114         p = (char *)val->bv_val;
4115         e = p + val->bv_len;
4116
4117         /* key */
4118         for (; ( p < e ) && ( *p != '=' ); p++ ) {
4119                 if ( !AD_CHAR( *p ) ) {
4120                         return LDAP_INVALID_SYNTAX;
4121                 }
4122         }
4123
4124         if ( *p != '=' ) {
4125                 return LDAP_INVALID_SYNTAX;
4126         }
4127
4128         /* server */
4129         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
4130                 if ( !AD_CHAR( *p ) ) {
4131                         return LDAP_INVALID_SYNTAX;
4132                 }
4133         }
4134
4135         if ( *p != ':' ) {
4136                 return LDAP_INVALID_SYNTAX;
4137         }
4138
4139         /* path */
4140         for ( p++; p < e; p++ ) {
4141                 if ( !SLAP_PRINTABLE( *p ) ) {
4142                         return LDAP_INVALID_SYNTAX;
4143                 }
4144         }
4145
4146         return LDAP_SUCCESS;
4147 }
4148
4149 static int
4150 firstComponentNormalize(
4151         slap_mask_t usage,
4152         Syntax *syntax,
4153         MatchingRule *mr,
4154         struct berval *val,
4155         struct berval *normalized,
4156         void *ctx )
4157 {
4158         int rc;
4159         struct berval comp;
4160         ber_len_t len;
4161
4162         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
4163                 ber_dupbv_x( normalized, val, ctx );
4164                 return LDAP_SUCCESS;
4165         }
4166
4167         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4168
4169         if( val->bv_val[0] != '(' /*')'*/ &&
4170                 val->bv_val[0] != '{' /*'}'*/ )
4171         {
4172                 return LDAP_INVALID_SYNTAX;
4173         }
4174
4175         /* trim leading white space */
4176         for( len=1;
4177                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
4178                 len++ )
4179         {
4180                 /* empty */
4181         }
4182
4183         /* grab next word */
4184         comp.bv_val = &val->bv_val[len];
4185         len = val->bv_len - len;
4186         for( comp.bv_len = 0;
4187                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
4188                 comp.bv_len++ )
4189         {
4190                 /* empty */
4191         }
4192
4193         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
4194                 rc = numericoidValidate( NULL, &comp );
4195         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
4196                 rc = integerValidate( NULL, &comp );
4197         } else {
4198                 rc = LDAP_INVALID_SYNTAX;
4199         }
4200         
4201
4202         if( rc == LDAP_SUCCESS ) {
4203                 ber_dupbv_x( normalized, &comp, ctx );
4204         }
4205
4206         return rc;
4207 }
4208
4209 static char *country_gen_syn[] = {
4210         "1.3.6.1.4.1.1466.115.121.1.15",
4211         "1.3.6.1.4.1.1466.115.121.1.26",
4212         "1.3.6.1.4.1.1466.115.121.1.44",
4213         NULL
4214 };
4215
4216 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
4217 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
4218
4219 static slap_syntax_defs_rec syntax_defs[] = {
4220         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
4221                 X_BINARY X_NOT_H_R ")",
4222                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
4223         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
4224                 0, NULL, NULL, NULL},
4225         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
4226                 0, NULL, NULL, NULL},
4227         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
4228                 X_NOT_H_R ")",
4229                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4230         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
4231                 X_NOT_H_R ")",
4232                 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4233         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
4234                 0, NULL, bitStringValidate, NULL },
4235         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
4236                 0, NULL, booleanValidate, NULL},
4237         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
4238                 X_BINARY X_NOT_H_R ")",
4239                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4240                 NULL, certificateValidate, NULL},
4241         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
4242                 X_BINARY X_NOT_H_R ")",
4243                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4244                 NULL, certificateListValidate, NULL},
4245         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4246                 X_BINARY X_NOT_H_R ")",
4247                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4248                 NULL, sequenceValidate, NULL},
4249 #if 0   /* need to go __after__ printableString */
4250         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4251                 0, "1.3.6.1.4.1.1466.115.121.1.44",
4252                 countryStringValidate, NULL},
4253 #endif
4254         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4255                 0, NULL, dnValidate, dnPretty},
4256         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
4257                 0, NULL, rdnValidate, rdnPretty},
4258 #ifdef LDAP_COMP_MATCH
4259         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
4260                 0, NULL, allComponentsValidate, NULL},
4261         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
4262                 0, NULL, componentFilterValidate, NULL},
4263 #endif
4264         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4265                 0, NULL, NULL, NULL},
4266         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4267                 0, NULL, deliveryMethodValidate, NULL},
4268         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4269                 0, NULL, UTF8StringValidate, NULL},
4270         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4271                 0, NULL, NULL, NULL},
4272         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4273                 0, NULL, NULL, NULL},
4274         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4275                 0, NULL, NULL, NULL},
4276         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4277                 0, NULL, NULL, NULL},
4278         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4279                 0, NULL, NULL, NULL},
4280         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4281                 0, NULL, printablesStringValidate, NULL},
4282         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4283                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
4284         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4285                 0, NULL, generalizedTimeValidate, NULL},
4286         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4287                 0, NULL, NULL, NULL},
4288         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4289                 0, NULL, IA5StringValidate, NULL},
4290         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4291                 0, NULL, integerValidate, NULL},
4292         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4293                 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4294         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4295                 0, NULL, NULL, NULL},
4296         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4297                 0, NULL, NULL, NULL},
4298         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4299                 0, NULL, NULL, NULL},
4300         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4301                 0, NULL, NULL, NULL},
4302         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4303                 0, NULL, NULL, NULL},
4304         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4305                 0, NULL, nameUIDValidate, nameUIDPretty },
4306         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4307                 0, NULL, NULL, NULL},
4308         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4309                 0, NULL, numericStringValidate, NULL},
4310         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4311                 0, NULL, NULL, NULL},
4312         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4313                 0, NULL, numericoidValidate, NULL},
4314         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4315                 0, NULL, IA5StringValidate, NULL},
4316         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4317                 0, NULL, blobValidate, NULL},
4318         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4319                 0, NULL, UTF8StringValidate, NULL},
4320         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4321                 0, NULL, NULL, NULL},
4322         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4323                 0, NULL, NULL, NULL},
4324         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4325                 0, NULL, printableStringValidate, NULL},
4326         /* moved here because now depends on Directory String, IA5 String 
4327          * and Printable String */
4328         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4329                 0, country_gen_syn, countryStringValidate, NULL},
4330         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
4331 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
4332                 0, NULL, subtreeSpecificationValidate, NULL},
4333         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4334                 X_BINARY X_NOT_H_R ")",
4335                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4336         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4337                 0, NULL, printableStringValidate, NULL},
4338         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4339                 0, NULL, NULL, NULL},
4340         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4341                 0, NULL, printablesStringValidate, NULL},
4342 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4343         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4344                 0, NULL, utcTimeValidate, NULL},
4345 #endif
4346         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4347                 0, NULL, NULL, NULL},
4348         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4349                 0, NULL, NULL, NULL},
4350         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4351                 0, NULL, NULL, NULL},
4352         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4353                 0, NULL, NULL, NULL},
4354         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4355                 0, NULL, NULL, NULL},
4356
4357         /* RFC 2307 NIS Syntaxes */
4358         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
4359                 0, NULL, nisNetgroupTripleValidate, NULL},
4360         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
4361                 0, NULL, bootParameterValidate, NULL},
4362
4363         /* draft-zeilenga-ldap-x509 */
4364         {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
4365                 SLAP_SYNTAX_HIDE, NULL,
4366                 serialNumberAndIssuerValidate,
4367                 serialNumberAndIssuerPretty},
4368         {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
4369                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4370         {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
4371                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4372         {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
4373                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4374         {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
4375                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4376         {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
4377                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4378         {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
4379                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4380
4381 #ifdef SLAPD_AUTHPASSWD
4382         /* needs updating */
4383         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4384                 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4385 #endif
4386
4387         {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
4388                 0, NULL, UUIDValidate, UUIDPretty},
4389
4390         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
4391                 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
4392
4393         {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
4394                 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
4395
4396         /* OpenLDAP Void Syntax */
4397         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4398                 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
4399
4400         /* FIXME: OID is unused, but not registered yet */
4401         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
4402                 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
4403
4404         {NULL, 0, NULL, NULL, NULL}
4405 };
4406
4407 char *csnSIDMatchSyntaxes[] = {
4408         "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
4409         NULL
4410 };
4411 char *certificateExactMatchSyntaxes[] = {
4412         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4413         NULL
4414 };
4415 #ifdef LDAP_COMP_MATCH
4416 char *componentFilterMatchSyntaxes[] = {
4417         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4418         NULL
4419 };
4420 #endif
4421 char *directoryStringSyntaxes[] = {
4422         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
4423         NULL
4424 };
4425 char *integerFirstComponentMatchSyntaxes[] = {
4426         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
4427         "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
4428         NULL
4429 };
4430 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
4431         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
4432         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
4433         "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
4434         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
4435         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
4436         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
4437         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
4438         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
4439         NULL
4440 };
4441
4442 /*
4443  * Other matching rules in X.520 that we do not use (yet):
4444  *
4445  * 2.5.13.25    uTCTimeMatch
4446  * 2.5.13.26    uTCTimeOrderingMatch
4447  * 2.5.13.31*   directoryStringFirstComponentMatch
4448  * 2.5.13.32*   wordMatch
4449  * 2.5.13.33*   keywordMatch
4450  * 2.5.13.36+   certificatePairExactMatch
4451  * 2.5.13.37+   certificatePairMatch
4452  * 2.5.13.38+   certificateListExactMatch
4453  * 2.5.13.39+   certificateListMatch
4454  * 2.5.13.40+   algorithmIdentifierMatch
4455  * 2.5.13.41*   storedPrefixMatch
4456  * 2.5.13.42    attributeCertificateMatch
4457  * 2.5.13.43    readerAndKeyIDMatch
4458  * 2.5.13.44    attributeIntegrityMatch
4459  *
4460  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
4461  * (+) described in draft-zeilenga-ldap-x509
4462  */
4463 static slap_mrule_defs_rec mrule_defs[] = {
4464         /*
4465          * EQUALITY matching rules must be listed after associated APPROX
4466          * matching rules.  So, we list all APPROX matching rules first.
4467          */
4468         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4469                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4470                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4471                 NULL, NULL, directoryStringApproxMatch,
4472                 directoryStringApproxIndexer, directoryStringApproxFilter,
4473                 NULL},
4474
4475         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4476                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4477                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4478                 NULL, NULL, IA5StringApproxMatch,
4479                 IA5StringApproxIndexer, IA5StringApproxFilter,
4480                 NULL},
4481
4482         /*
4483          * Other matching rules
4484          */
4485         
4486         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4487                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4488                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4489                 NULL, NULL, octetStringMatch,
4490                 octetStringIndexer, octetStringFilter,
4491                 NULL },
4492
4493         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4494                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4495                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4496                 NULL, dnNormalize, dnMatch,
4497                 octetStringIndexer, octetStringFilter,
4498                 NULL },
4499
4500         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
4501                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4502                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4503                 NULL, dnNormalize, dnRelativeMatch,
4504                 NULL, NULL,
4505                 NULL },
4506
4507         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
4508                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4509                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4510                 NULL, dnNormalize, dnRelativeMatch,
4511                 NULL, NULL,
4512                 NULL },
4513
4514         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
4515                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4516                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4517                 NULL, dnNormalize, dnRelativeMatch,
4518                 NULL, NULL,
4519                 NULL },
4520
4521         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
4522                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4523                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4524                 NULL, dnNormalize, dnRelativeMatch,
4525                 NULL, NULL,
4526                 NULL },
4527
4528         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
4529                 "SYNTAX 1.2.36.79672281.1.5.0 )",
4530                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4531                 NULL, rdnNormalize, rdnMatch,
4532                 octetStringIndexer, octetStringFilter,
4533                 NULL },
4534
4535 #ifdef LDAP_COMP_MATCH
4536         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
4537                 "SYNTAX 1.2.36.79672281.1.5.2 )",
4538                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
4539                 NULL, NULL , componentFilterMatch,
4540                 octetStringIndexer, octetStringFilter,
4541                 NULL },
4542
4543         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
4544                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4545                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4546                 NULL, NULL , allComponentsMatch,
4547                 octetStringIndexer, octetStringFilter,
4548                 NULL },
4549
4550         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
4551                 "SYNTAX 1.2.36.79672281.1.5.3 )",
4552                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4553                 NULL, NULL , directoryComponentsMatch,
4554                 octetStringIndexer, octetStringFilter,
4555                 NULL },
4556 #endif
4557
4558         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4559                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4560                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4561                 NULL, UTF8StringNormalize, octetStringMatch,
4562                 octetStringIndexer, octetStringFilter,
4563                 directoryStringApproxMatchOID },
4564
4565         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4566                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4567                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4568                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4569                 NULL, NULL,
4570                 "caseIgnoreMatch" },
4571
4572         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4573                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4574                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4575                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4576                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4577                 "caseIgnoreMatch" },
4578
4579         {"( 2.5.13.5 NAME 'caseExactMatch' "
4580                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4581                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4582                 NULL, UTF8StringNormalize, octetStringMatch,
4583                 octetStringIndexer, octetStringFilter,
4584                 directoryStringApproxMatchOID },
4585
4586         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4587                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4588                 SLAP_MR_ORDERING, directoryStringSyntaxes,
4589                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4590                 NULL, NULL,
4591                 "caseExactMatch" },
4592
4593         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4594                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4595                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4596                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4597                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4598                 "caseExactMatch" },
4599
4600         {"( 2.5.13.8 NAME 'numericStringMatch' "
4601                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4602                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4603                 NULL, numericStringNormalize, octetStringMatch,
4604                 octetStringIndexer, octetStringFilter,
4605                 NULL },
4606
4607         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
4608                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4609                 SLAP_MR_ORDERING, NULL,
4610                 NULL, numericStringNormalize, octetStringOrderingMatch,
4611                 NULL, NULL,
4612                 "numericStringMatch" },
4613
4614         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4615                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4616                 SLAP_MR_SUBSTR, NULL,
4617                 NULL, numericStringNormalize, octetStringSubstringsMatch,
4618                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4619                 "numericStringMatch" },
4620
4621         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4622                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4623                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4624                 NULL, NULL, NULL, NULL, NULL, NULL },
4625
4626         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4627                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4628                 SLAP_MR_SUBSTR, NULL,
4629                 NULL, NULL, NULL, NULL, NULL,
4630                 "caseIgnoreListMatch" },
4631
4632         {"( 2.5.13.13 NAME 'booleanMatch' "
4633                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
4634                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4635                 NULL, NULL, booleanMatch,
4636                 octetStringIndexer, octetStringFilter,
4637                 NULL },
4638
4639         {"( 2.5.13.14 NAME 'integerMatch' "
4640                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4641                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4642                 NULL, NULL, integerMatch,
4643                 octetStringIndexer, octetStringFilter,
4644                 NULL },
4645
4646         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
4647                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4648                 SLAP_MR_ORDERING, NULL,
4649                 NULL, NULL, integerMatch,
4650                 NULL, NULL,
4651                 "integerMatch" },
4652
4653         {"( 2.5.13.16 NAME 'bitStringMatch' "
4654                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
4655                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4656                 NULL, NULL, octetStringMatch,
4657                 octetStringIndexer, octetStringFilter,
4658                 NULL },
4659
4660         {"( 2.5.13.17 NAME 'octetStringMatch' "
4661                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4662                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4663                 NULL, NULL, octetStringMatch,
4664                 octetStringIndexer, octetStringFilter,
4665                 NULL },
4666
4667         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
4668                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4669                 SLAP_MR_ORDERING, NULL,
4670                 NULL, NULL, octetStringOrderingMatch,
4671                 NULL, NULL,
4672                 "octetStringMatch" },
4673
4674         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
4675                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4676                 SLAP_MR_SUBSTR, NULL,
4677                 NULL, NULL, octetStringSubstringsMatch,
4678                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4679                 "octetStringMatch" },
4680
4681         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
4682                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
4683                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4684                 NULL,
4685                 telephoneNumberNormalize, octetStringMatch,
4686                 octetStringIndexer, octetStringFilter,
4687                 NULL },
4688
4689         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
4690                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4691                 SLAP_MR_SUBSTR, NULL,
4692                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
4693                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4694                 "telephoneNumberMatch" },
4695
4696         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
4697                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
4698                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4699                 NULL, NULL, NULL, NULL, NULL, NULL },
4700
4701         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
4702                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
4703                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4704                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
4705                 uniqueMemberIndexer, uniqueMemberFilter,
4706                 NULL },
4707
4708         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
4709                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
4710                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4711                 NULL, NULL, NULL, NULL, NULL, NULL },
4712
4713         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
4714                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4715                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
4716                 NULL, generalizedTimeNormalize, octetStringMatch,
4717                 generalizedTimeIndexer, generalizedTimeFilter,
4718                 NULL },
4719
4720         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
4721                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4722                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
4723                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
4724                 NULL, NULL,
4725                 "generalizedTimeMatch" },
4726
4727         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
4728                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4729                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4730                         integerFirstComponentMatchSyntaxes,
4731                 NULL, firstComponentNormalize, integerMatch,
4732                 octetStringIndexer, octetStringFilter,
4733                 NULL },
4734
4735         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
4736                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4737                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4738                         objectIdentifierFirstComponentMatchSyntaxes,
4739                 NULL, firstComponentNormalize, octetStringMatch,
4740                 octetStringIndexer, octetStringFilter,
4741                 NULL },
4742
4743         {"( 2.5.13.34 NAME 'certificateExactMatch' "
4744                 "SYNTAX 1.3.6.1.1.15.1 )",
4745                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
4746                 NULL, certificateExactNormalize, octetStringMatch,
4747                 octetStringIndexer, octetStringFilter,
4748                 NULL },
4749
4750         {"( 2.5.13.35 NAME 'certificateMatch' "
4751                 "SYNTAX 1.3.6.1.1.15.2 )",
4752                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4753                 NULL, NULL, NULL, NULL, NULL,
4754                 NULL },
4755
4756         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
4757                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4758                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4759                 NULL, IA5StringNormalize, octetStringMatch,
4760                 octetStringIndexer, octetStringFilter,
4761                 IA5StringApproxMatchOID },
4762
4763         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
4764                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4765                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4766                 NULL, IA5StringNormalize, octetStringMatch,
4767                 octetStringIndexer, octetStringFilter,
4768                 IA5StringApproxMatchOID },
4769
4770         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
4771                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4772                 SLAP_MR_SUBSTR, NULL,
4773                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
4774                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4775                 "caseIgnoreIA5Match" },
4776
4777         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
4778                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4779                 SLAP_MR_SUBSTR, NULL,
4780                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
4781                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4782                 "caseExactIA5Match" },
4783
4784 #ifdef SLAPD_AUTHPASSWD
4785         /* needs updating */
4786         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
4787                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4788                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
4789                 NULL, NULL, authPasswordMatch,
4790                 NULL, NULL,
4791                 NULL},
4792 #endif
4793
4794         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
4795                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4796                 SLAP_MR_EXT, NULL,
4797                 NULL, NULL, integerBitAndMatch,
4798                 NULL, NULL,
4799                 "integerMatch" },
4800
4801         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
4802                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4803                 SLAP_MR_EXT, NULL,
4804                 NULL, NULL, integerBitOrMatch,
4805                 NULL, NULL,
4806                 "integerMatch" },
4807
4808         {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
4809                 "SYNTAX 1.3.6.1.1.16.1 )",
4810                 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
4811                 NULL, UUIDNormalize, octetStringMatch,
4812                 octetStringIndexer, octetStringFilter,
4813                 NULL},
4814
4815         {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
4816                 "SYNTAX 1.3.6.1.1.16.1 )",
4817                 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
4818                 NULL, UUIDNormalize, octetStringOrderingMatch,
4819                 octetStringIndexer, octetStringFilter,
4820                 "UUIDMatch"},
4821
4822         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
4823                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
4824                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
4825                 NULL, csnNormalize, csnMatch,
4826                 csnIndexer, csnFilter,
4827                 NULL},
4828
4829         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
4830                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
4831                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
4832                 NULL, NULL, csnOrderingMatch,
4833                 NULL, NULL,
4834                 "CSNMatch" },
4835
4836         {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
4837                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
4838                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
4839                 NULL, csnSidNormalize, octetStringMatch,
4840                 octetStringIndexer, octetStringFilter,
4841                 NULL },
4842
4843         /* FIXME: OID is unused, but not registered yet */
4844         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
4845                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
4846                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
4847                 NULL, authzNormalize, authzMatch,
4848                 NULL, NULL,
4849                 NULL},
4850
4851         {NULL, SLAP_MR_NONE, NULL,
4852                 NULL, NULL, NULL, NULL, NULL,
4853                 NULL }
4854 };
4855
4856 int
4857 slap_schema_init( void )
4858 {
4859         int             res;
4860         int             i;
4861
4862         /* we should only be called once (from main) */
4863         assert( schema_init_done == 0 );
4864
4865         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
4866                 res = register_syntax( &syntax_defs[i] );
4867
4868                 if ( res ) {
4869                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
4870                                  syntax_defs[i].sd_desc );
4871                         return LDAP_OTHER;
4872                 }
4873         }
4874
4875         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
4876                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
4877                         mrule_defs[i].mrd_compat_syntaxes == NULL )
4878                 {
4879                         fprintf( stderr,
4880                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
4881                                  mrule_defs[i].mrd_desc );
4882                         continue;
4883                 }
4884
4885                 res = register_matching_rule( &mrule_defs[i] );
4886
4887                 if ( res ) {
4888                         fprintf( stderr,
4889                                 "slap_schema_init: Error registering matching rule %s\n",
4890                                  mrule_defs[i].mrd_desc );
4891                         return LDAP_OTHER;
4892                 }
4893         }
4894
4895         res = slap_schema_load();
4896         schema_init_done = 1;
4897         return res;
4898 }
4899
4900 void
4901 schema_destroy( void )
4902 {
4903         oidm_destroy();
4904         oc_destroy();
4905         at_destroy();
4906         mr_destroy();
4907         mru_destroy();
4908         syn_destroy();
4909
4910         if( schema_init_done ) {
4911                 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
4912                 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
4913         }
4914 }