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