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