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