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