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