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