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