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