]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
don't trust strchr/strrchr with bervals
[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-2005 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
31 #include "ldap_utf8.h"
32
33 #ifdef HAVE_TLS
34 #include <openssl/x509.h>
35 #include <openssl/err.h>
36 #include <openssl/rsa.h>
37 #include <openssl/crypto.h>
38 #include <openssl/pem.h>
39 #include <openssl/bio.h>
40 #include <openssl/asn1.h>
41 #include <openssl/x509v3.h>
42 #include <openssl/ssl.h>
43 #endif
44
45 #include "lutil.h"
46 #include "lutil_hash.h"
47 #define HASH_BYTES                              LUTIL_HASH_BYTES
48 #define HASH_CONTEXT                    lutil_HASH_CTX
49 #define HASH_Init(c)                    lutil_HASHInit(c)
50 #define HASH_Update(c,buf,len)  lutil_HASHUpdate(c,buf,len)
51 #define HASH_Final(d,c)                 lutil_HASHFinal(d,c)
52
53 /* approx matching rules */
54 #define directoryStringApproxMatchOID   "1.3.6.1.4.1.4203.666.4.4"
55 #define directoryStringApproxMatch              approxMatch
56 #define directoryStringApproxIndexer    approxIndexer
57 #define directoryStringApproxFilter             approxFilter
58 #define IA5StringApproxMatchOID                 "1.3.6.1.4.1.4203.666.4.5"
59 #define IA5StringApproxMatch                    approxMatch
60 #define IA5StringApproxIndexer                  approxIndexer
61 #define IA5StringApproxFilter                   approxFilter
62
63 /* Change Sequence Number (CSN) - much of this will change */
64 #define csnValidate                             blobValidate
65 #define csnMatch                                octetStringMatch
66 #define csnOrderingMatch                octetStringOrderingMatch
67 #define csnIndexer                              generalizedTimeIndexer
68 #define csnFilter                               generalizedTimeFilter
69
70 #ifdef SLAP_AUTHZ_SYNTAX
71 /* FIXME: temporary */
72 #define authzMatch                              octetStringMatch
73 #endif /* SLAP_AUTHZ_SYNTAX */
74
75 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
76 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
77 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
78 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
79
80 ldap_pvt_thread_mutex_t ad_undef_mutex;
81 ldap_pvt_thread_mutex_t oc_undef_mutex;
82
83 static int
84 inValidate(
85         Syntax *syntax,
86         struct berval *in )
87 {
88         /* no value allowed */
89         return LDAP_INVALID_SYNTAX;
90 }
91
92 static int
93 blobValidate(
94         Syntax *syntax,
95         struct berval *in )
96 {
97         /* any value allowed */
98         return LDAP_SUCCESS;
99 }
100
101 #define berValidate blobValidate
102
103 static int
104 sequenceValidate(
105         Syntax *syntax,
106         struct berval *in )
107 {
108         if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
109         if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
110
111         return LDAP_SUCCESS;
112 }
113
114
115 #ifdef HAVE_TLS
116 static int certificateValidate( Syntax *syntax, struct berval *in )
117 {
118         X509 *xcert=NULL;
119         unsigned char *p = (unsigned char *)in->bv_val;
120  
121         xcert = d2i_X509(NULL, &p, in->bv_len);
122         if ( !xcert ) return LDAP_INVALID_SYNTAX;
123         X509_free(xcert);
124         return LDAP_SUCCESS;
125 }
126 #else
127 #define certificateValidate sequenceValidate
128 #endif
129
130 int
131 octetStringMatch(
132         int *matchp,
133         slap_mask_t flags,
134         Syntax *syntax,
135         MatchingRule *mr,
136         struct berval *value,
137         void *assertedValue )
138 {
139         struct berval *asserted = (struct berval *) assertedValue;
140         int match = value->bv_len - asserted->bv_len;
141
142         if( match == 0 ) {
143                 match = memcmp( value->bv_val, asserted->bv_val, value->bv_len );
144         }
145
146         *matchp = match;
147         return LDAP_SUCCESS;
148 }
149
150 static int
151 octetStringOrderingMatch(
152         int *matchp,
153         slap_mask_t flags,
154         Syntax *syntax,
155         MatchingRule *mr,
156         struct berval *value,
157         void *assertedValue )
158 {
159         struct berval *asserted = (struct berval *) assertedValue;
160         ber_len_t v_len  = value->bv_len;
161         ber_len_t av_len = asserted->bv_len;
162
163         int match = memcmp( value->bv_val, asserted->bv_val,
164                 (v_len < av_len ? v_len : av_len) );
165
166         if( match == 0 ) match = v_len - av_len;
167
168         *matchp = match;
169         return LDAP_SUCCESS;
170 }
171
172 static void
173 hashPreset(
174         HASH_CONTEXT *HASHcontext,
175         struct berval *prefix,
176         char pre,
177         Syntax *syntax,
178         MatchingRule *mr)
179 {
180         HASH_Init(HASHcontext);
181         if(prefix && prefix->bv_len > 0) {
182                 HASH_Update(HASHcontext,
183                         (unsigned char *)prefix->bv_val, prefix->bv_len);
184         }
185         if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
186         HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
187         HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
188         return;
189 }
190
191 static void
192 hashIter(
193         HASH_CONTEXT *HASHcontext,
194         unsigned char *HASHdigest,
195         unsigned char *value,
196         int len)
197 {
198         HASH_CONTEXT ctx = *HASHcontext;
199         HASH_Update( &ctx, value, len );
200         HASH_Final( HASHdigest, &ctx );
201 }
202
203 /* Index generation function */
204 int octetStringIndexer(
205         slap_mask_t use,
206         slap_mask_t flags,
207         Syntax *syntax,
208         MatchingRule *mr,
209         struct berval *prefix,
210         BerVarray values,
211         BerVarray *keysp,
212         void *ctx )
213 {
214         int i;
215         size_t slen, mlen;
216         BerVarray keys;
217         HASH_CONTEXT HASHcontext;
218         unsigned char HASHdigest[HASH_BYTES];
219         struct berval digest;
220         digest.bv_val = (char *)HASHdigest;
221         digest.bv_len = sizeof(HASHdigest);
222
223         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
224                 /* just count them */
225         }
226
227         /* we should have at least one value at this point */
228         assert( i > 0 );
229
230         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
231
232         slen = syntax->ssyn_oidlen;
233         mlen = mr->smr_oidlen;
234
235         hashPreset( &HASHcontext, prefix, 0, syntax, mr);
236         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
237                 hashIter( &HASHcontext, HASHdigest,
238                         (unsigned char *)values[i].bv_val, values[i].bv_len );
239                 ber_dupbv_x( &keys[i], &digest, ctx );
240         }
241
242         BER_BVZERO( &keys[i] );
243
244         *keysp = keys;
245
246         return LDAP_SUCCESS;
247 }
248
249 /* Index generation function */
250 int octetStringFilter(
251         slap_mask_t use,
252         slap_mask_t flags,
253         Syntax *syntax,
254         MatchingRule *mr,
255         struct berval *prefix,
256         void * assertedValue,
257         BerVarray *keysp,
258         void *ctx )
259 {
260         size_t slen, mlen;
261         BerVarray keys;
262         HASH_CONTEXT HASHcontext;
263         unsigned char HASHdigest[HASH_BYTES];
264         struct berval *value = (struct berval *) assertedValue;
265         struct berval digest;
266         digest.bv_val = (char *)HASHdigest;
267         digest.bv_len = sizeof(HASHdigest);
268
269         slen = syntax->ssyn_oidlen;
270         mlen = mr->smr_oidlen;
271
272         keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
273
274         hashPreset( &HASHcontext, prefix, 0, syntax, mr );
275         hashIter( &HASHcontext, HASHdigest,
276                 (unsigned char *)value->bv_val, value->bv_len );
277
278         ber_dupbv_x( keys, &digest, ctx );
279         BER_BVZERO( &keys[1] );
280
281         *keysp = keys;
282
283         return LDAP_SUCCESS;
284 }
285
286 static int
287 octetStringSubstringsMatch(
288         int *matchp,
289         slap_mask_t flags,
290         Syntax *syntax,
291         MatchingRule *mr,
292         struct berval *value,
293         void *assertedValue )
294 {
295         int match = 0;
296         SubstringsAssertion *sub = assertedValue;
297         struct berval left = *value;
298         int i;
299         ber_len_t inlen = 0;
300
301         /* Add up asserted input length */
302         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
303                 inlen += sub->sa_initial.bv_len;
304         }
305         if ( sub->sa_any ) {
306                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
307                         inlen += sub->sa_any[i].bv_len;
308                 }
309         }
310         if ( !BER_BVISNULL( &sub->sa_final ) ) {
311                 inlen += sub->sa_final.bv_len;
312         }
313
314         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
315                 if ( inlen > left.bv_len ) {
316                         match = 1;
317                         goto done;
318                 }
319
320                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
321                         sub->sa_initial.bv_len );
322
323                 if ( match != 0 ) {
324                         goto done;
325                 }
326
327                 left.bv_val += sub->sa_initial.bv_len;
328                 left.bv_len -= sub->sa_initial.bv_len;
329                 inlen -= sub->sa_initial.bv_len;
330         }
331
332         if ( !BER_BVISNULL( &sub->sa_final ) ) {
333                 if ( inlen > left.bv_len ) {
334                         match = 1;
335                         goto done;
336                 }
337
338                 match = memcmp( sub->sa_final.bv_val,
339                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
340                         sub->sa_final.bv_len );
341
342                 if ( match != 0 ) {
343                         goto done;
344                 }
345
346                 left.bv_len -= sub->sa_final.bv_len;
347                 inlen -= sub->sa_final.bv_len;
348         }
349
350         if ( sub->sa_any ) {
351                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
352                         ber_len_t idx;
353                         char *p;
354
355 retry:
356                         if ( inlen > left.bv_len ) {
357                                 /* not enough length */
358                                 match = 1;
359                                 goto done;
360                         }
361
362                         if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
363                                 continue;
364                         }
365
366                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
367
368                         if( p == NULL ) {
369                                 match = 1;
370                                 goto done;
371                         }
372
373                         idx = p - left.bv_val;
374
375                         if ( idx >= left.bv_len ) {
376                                 /* this shouldn't happen */
377                                 return LDAP_OTHER;
378                         }
379
380                         left.bv_val = p;
381                         left.bv_len -= idx;
382
383                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
384                                 /* not enough left */
385                                 match = 1;
386                                 goto done;
387                         }
388
389                         match = memcmp( left.bv_val,
390                                 sub->sa_any[i].bv_val,
391                                 sub->sa_any[i].bv_len );
392
393                         if ( match != 0 ) {
394                                 left.bv_val++;
395                                 left.bv_len--;
396                                 goto retry;
397                         }
398
399                         left.bv_val += sub->sa_any[i].bv_len;
400                         left.bv_len -= sub->sa_any[i].bv_len;
401                         inlen -= sub->sa_any[i].bv_len;
402                 }
403         }
404
405 done:
406         *matchp = match;
407         return LDAP_SUCCESS;
408 }
409
410 /* Substrings Index generation function */
411 static int
412 octetStringSubstringsIndexer(
413         slap_mask_t use,
414         slap_mask_t flags,
415         Syntax *syntax,
416         MatchingRule *mr,
417         struct berval *prefix,
418         BerVarray values,
419         BerVarray *keysp,
420         void *ctx )
421 {
422         ber_len_t i, nkeys;
423         size_t slen, mlen;
424         BerVarray keys;
425
426         HASH_CONTEXT HCany, HCini, HCfin;
427         unsigned char HASHdigest[HASH_BYTES];
428         struct berval digest;
429         digest.bv_val = (char *)HASHdigest;
430         digest.bv_len = sizeof(HASHdigest);
431
432         nkeys = 0;
433
434         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
435                 /* count number of indices to generate */
436                 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
437                         if( values[i].bv_len >= index_substr_if_maxlen ) {
438                                 nkeys += index_substr_if_maxlen -
439                                         (index_substr_if_minlen - 1);
440                         } else if( values[i].bv_len >= index_substr_if_minlen ) {
441                                 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
442                         }
443                 }
444
445                 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
446                         if( values[i].bv_len >= index_substr_any_len ) {
447                                 nkeys += values[i].bv_len - (index_substr_any_len - 1);
448                         }
449                 }
450
451                 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
452                         if( values[i].bv_len >= index_substr_if_maxlen ) {
453                                 nkeys += index_substr_if_maxlen -
454                                         (index_substr_if_minlen - 1);
455                         } else if( values[i].bv_len >= index_substr_if_minlen ) {
456                                 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
457                         }
458                 }
459         }
460
461         if( nkeys == 0 ) {
462                 /* no keys to generate */
463                 *keysp = NULL;
464                 return LDAP_SUCCESS;
465         }
466
467         keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
468
469         slen = syntax->ssyn_oidlen;
470         mlen = mr->smr_oidlen;
471
472         if ( flags & SLAP_INDEX_SUBSTR_ANY )
473                 hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
474         if( flags & SLAP_INDEX_SUBSTR_INITIAL )
475                 hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
476         if( flags & SLAP_INDEX_SUBSTR_FINAL )
477                 hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
478
479         nkeys = 0;
480         for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
481                 ber_len_t j,max;
482
483                 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
484                         ( values[i].bv_len >= index_substr_any_len ) )
485                 {
486                         max = values[i].bv_len - (index_substr_any_len - 1);
487
488                         for( j=0; j<max; j++ ) {
489                                 hashIter( &HCany, HASHdigest,
490                                         (unsigned char *)&values[i].bv_val[j],
491                                         index_substr_any_len );
492                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
493                         }
494                 }
495
496                 /* skip if too short */ 
497                 if( values[i].bv_len < index_substr_if_minlen ) continue;
498
499                 max = index_substr_if_maxlen < values[i].bv_len
500                         ? index_substr_if_maxlen : values[i].bv_len;
501
502                 for( j=index_substr_if_minlen; j<=max; j++ ) {
503
504                         if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
505                                 hashIter( &HCini, HASHdigest,
506                                         (unsigned char *)values[i].bv_val, j );
507                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
508                         }
509
510                         if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
511                                 hashIter( &HCfin, HASHdigest,
512                                         (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
513                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
514                         }
515
516                 }
517         }
518
519         if( nkeys > 0 ) {
520                 BER_BVZERO( &keys[nkeys] );
521                 *keysp = keys;
522         } else {
523                 ch_free( keys );
524                 *keysp = NULL;
525         }
526
527         return LDAP_SUCCESS;
528 }
529
530 static int
531 octetStringSubstringsFilter (
532         slap_mask_t use,
533         slap_mask_t flags,
534         Syntax *syntax,
535         MatchingRule *mr,
536         struct berval *prefix,
537         void * assertedValue,
538         BerVarray *keysp,
539         void *ctx)
540 {
541         SubstringsAssertion *sa;
542         char pre;
543         ber_len_t nkeys = 0;
544         size_t slen, mlen, klen;
545         BerVarray keys;
546         HASH_CONTEXT HASHcontext;
547         unsigned char HASHdigest[HASH_BYTES];
548         struct berval *value;
549         struct berval digest;
550
551         sa = (SubstringsAssertion *) assertedValue;
552
553         if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
554                 !BER_BVISNULL( &sa->sa_initial ) &&
555                 sa->sa_initial.bv_len >= index_substr_if_minlen )
556         {
557                 nkeys++;
558                 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
559                         ( flags & SLAP_INDEX_SUBSTR_ANY ))
560                 {
561                         nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
562                 }
563         }
564
565         if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
566                 ber_len_t i;
567                 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
568                         if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
569                                 /* don't bother accounting with stepping */
570                                 nkeys += sa->sa_any[i].bv_len -
571                                         ( index_substr_any_len - 1 );
572                         }
573                 }
574         }
575
576         if( flags & SLAP_INDEX_SUBSTR_FINAL &&
577                 !BER_BVISNULL( &sa->sa_final ) &&
578                 sa->sa_final.bv_len >= index_substr_if_minlen )
579         {
580                 nkeys++;
581                 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
582                         ( flags & SLAP_INDEX_SUBSTR_ANY ))
583                 {
584                         nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
585                 }
586         }
587
588         if( nkeys == 0 ) {
589                 *keysp = NULL;
590                 return LDAP_SUCCESS;
591         }
592
593         digest.bv_val = (char *)HASHdigest;
594         digest.bv_len = sizeof(HASHdigest);
595
596         slen = syntax->ssyn_oidlen;
597         mlen = mr->smr_oidlen;
598
599         keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
600         nkeys = 0;
601
602         if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
603                 !BER_BVISNULL( &sa->sa_initial ) &&
604                 sa->sa_initial.bv_len >= index_substr_if_minlen )
605         {
606                 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
607                 value = &sa->sa_initial;
608
609                 klen = index_substr_if_maxlen < value->bv_len
610                         ? index_substr_if_maxlen : value->bv_len;
611
612                 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
613                 hashIter( &HASHcontext, HASHdigest,
614                         (unsigned char *)value->bv_val, klen );
615                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
616
617                 /* If initial is too long and we have subany indexed, use it
618                  * to match the excess...
619                  */
620                 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
621                 {
622                         ber_len_t j;
623                         pre = SLAP_INDEX_SUBSTR_PREFIX;
624                         hashPreset( &HASHcontext, prefix, pre, syntax, mr);
625                         for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
626                         {
627                                 hashIter( &HASHcontext, HASHdigest,
628                                         (unsigned char *)&value->bv_val[j], index_substr_any_len );
629                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
630                         }
631                 }
632         }
633
634         if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
635                 ber_len_t i, j;
636                 pre = SLAP_INDEX_SUBSTR_PREFIX;
637                 klen = index_substr_any_len;
638
639                 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
640                         if( sa->sa_any[i].bv_len < index_substr_any_len ) {
641                                 continue;
642                         }
643
644                         value = &sa->sa_any[i];
645
646                         hashPreset( &HASHcontext, prefix, pre, syntax, mr);
647                         for(j=0;
648                                 j <= value->bv_len - index_substr_any_len;
649                                 j += index_substr_any_step )
650                         {
651                                 hashIter( &HASHcontext, HASHdigest,
652                                         (unsigned char *)&value->bv_val[j], klen ); 
653                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
654                         }
655                 }
656         }
657
658         if( flags & SLAP_INDEX_SUBSTR_FINAL &&
659                 !BER_BVISNULL( &sa->sa_final ) &&
660                 sa->sa_final.bv_len >= index_substr_if_minlen )
661         {
662                 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
663                 value = &sa->sa_final;
664
665                 klen = index_substr_if_maxlen < value->bv_len
666                         ? index_substr_if_maxlen : value->bv_len;
667
668                 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
669                 hashIter( &HASHcontext, HASHdigest,
670                         (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
671                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
672
673                 /* If final is too long and we have subany indexed, use it
674                  * to match the excess...
675                  */
676                 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
677                 {
678                         ber_len_t j;
679                         pre = SLAP_INDEX_SUBSTR_PREFIX;
680                         hashPreset( &HASHcontext, prefix, pre, syntax, mr);
681                         for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
682                         {
683                                 hashIter( &HASHcontext, HASHdigest,
684                                         (unsigned char *)&value->bv_val[j], index_substr_any_len );
685                                 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
686                         }
687                 }
688         }
689
690         if( nkeys > 0 ) {
691                 BER_BVZERO( &keys[nkeys] );
692                 *keysp = keys;
693         } else {
694                 ch_free( keys );
695                 *keysp = NULL;
696         }
697
698         return LDAP_SUCCESS;
699 }
700
701 static int
702 bitStringValidate(
703         Syntax *syntax,
704         struct berval *in )
705 {
706         ber_len_t i;
707
708         /* very unforgiving validation, requires no normalization
709          * before simplistic matching
710          */
711         if( in->bv_len < 3 ) {
712                 return LDAP_INVALID_SYNTAX;
713         }
714
715         /*
716          * RFC 2252 section 6.3 Bit String
717          *      bitstring = "'" *binary-digit "'B"
718          *      binary-digit = "0" / "1"
719          * example: '0101111101'B
720          */
721         
722         if( in->bv_val[0] != '\'' ||
723                 in->bv_val[in->bv_len - 2] != '\'' ||
724                 in->bv_val[in->bv_len - 1] != 'B' )
725         {
726                 return LDAP_INVALID_SYNTAX;
727         }
728
729         for( i = in->bv_len - 3; i > 0; i-- ) {
730                 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
731                         return LDAP_INVALID_SYNTAX;
732                 }
733         }
734
735         return LDAP_SUCCESS;
736 }
737
738 /*
739  * Syntax is [RFC2252]:
740  *
741
742 6.3. Bit String
743
744    ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
745
746    Values in this syntax are encoded according to the following BNF:
747
748       bitstring = "'" *binary-digit "'B"
749
750       binary-digit = "0" / "1"
751
752    ... 
753
754 6.21. Name And Optional UID
755
756    ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
757
758    Values in this syntax are encoded according to the following BNF:
759
760       NameAndOptionalUID = DistinguishedName [ "#" bitstring ]
761
762    Although the '#' character may occur in a string representation of a
763    distinguished name, no additional special quoting is done.  This
764    syntax has been added subsequent to RFC 1778.
765
766    Example:
767
768       1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
769
770  *
771  * draft-ietf-ldapbis-syntaxes-xx.txt says:
772  *
773
774 3.3.2.  Bit String
775
776    A value of the Bit String syntax is a sequence of binary digits.  The
777    LDAP-specific encoding of a value of this syntax is defined by the
778    following ABNF:
779
780       BitString    = SQUOTE *binary-digit SQUOTE "B"
781
782       binary-digit = "0" / "1"
783
784    The <SQUOTE> rule is defined in [MODELS].
785
786       Example:
787          '0101111101'B
788
789    The LDAP definition for the Bit String syntax is:
790
791       ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
792
793    This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
794
795    ...
796
797 3.3.21.  Name and Optional UID
798
799    A value of the Name and Optional UID syntax is the distinguished name
800    [MODELS] of an entity optionally accompanied by a unique identifier
801    that serves to differentiate the entity from others with an identical
802    distinguished name.
803
804    The LDAP-specific encoding of a value of this syntax is defined by
805    the following ABNF:
806
807        NameAndOptionalUID = distinguishedName [ SHARP BitString ]
808
809    The <BitString> rule is defined in Section 3.3.2.  The
810    <distinguishedName> rule is defined in [LDAPDN].  The <SHARP> rule is
811    defined in [MODELS].
812
813    Note that although the '#' character may occur in the string
814    representation of a distinguished name, no additional escaping of
815    this character is performed when a <distinguishedName> is encoded in
816    a <NameAndOptionalUID>.
817
818       Example:
819          1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
820
821    The LDAP definition for the Name and Optional UID syntax is:
822
823       ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
824
825    This syntax corresponds to the NameAndOptionalUID ASN.1 type from
826    [X.520].
827
828  *
829  * draft-ietf-ldapbis-models-xx.txt [MODELS] says:
830  *
831
832 1.4. Common ABNF Productions
833
834   ...
835       SHARP   = %x23 ; octothorpe (or sharp sign) ("#")
836   ...
837       SQUOTE  = %x27 ; single quote ("'")
838   ...
839       
840  *
841  * Note: normalization strips any leading "0"s, unless the
842  * bit string is exactly "'0'B", so the normalized example,
843  * in slapd, would result in
844  * 
845  * 1.3.6.1.4.1.1466.0=#04024869,o=test,c=gb#'101'B
846  * 
847  * Since draft-ietf-ldapbis-dn-xx.txt clarifies that SHARP,
848  * i.e. "#", doesn't have to be escaped except when at the
849  * beginning of a value, the definition of Name and Optional
850  * UID appears to be flawed, because there is no clear means
851  * to determine whether the UID part is present or not.
852  *
853  * Example:
854  *
855  *      cn=Someone,dc=example,dc=com#'1'B
856  *
857  * could be either a NameAndOptionalUID with trailing UID, i.e.
858  *
859  *      DN = "cn=Someone,dc=example,dc=com"
860  *      UID = "'1'B"
861  * 
862  * or a NameAndOptionalUID with no trailing UID, and the AVA
863  * in the last RDN made of
864  *
865  *      attributeType = dc 
866  *      attributeValue = com#'1'B
867  *
868  * in fact "com#'1'B" is a valid IA5 string.
869  *
870  * As a consequence, current slapd code assumes that the
871  * presence of portions of a BitString at the end of the string 
872  * representation of a NameAndOptionalUID means a BitString
873  * is expected, and cause an error otherwise.  This is quite
874  * arbitrary, and might change in the future.
875  */
876
877
878 static int
879 nameUIDValidate(
880         Syntax *syntax,
881         struct berval *in )
882 {
883         int rc;
884         struct berval dn, uid;
885
886         if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
887
888         ber_dupbv( &dn, in );
889         if( !dn.bv_val ) return LDAP_OTHER;
890
891         /* if there's a "#", try bitStringValidate()... */
892         uid.bv_val = strrchr( dn.bv_val, '#' );
893         if ( !BER_BVISNULL( &uid ) ) {
894                 uid.bv_val++;
895                 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
896
897                 rc = bitStringValidate( NULL, &uid );
898                 if ( rc == LDAP_SUCCESS ) {
899                         /* in case of success, trim the UID,
900                          * otherwise treat it as part of the DN */
901                         dn.bv_len -= uid.bv_len + 1;
902                         uid.bv_val[-1] = '\0';
903                 }
904         }
905
906         rc = dnValidate( NULL, &dn );
907
908         ber_memfree( dn.bv_val );
909         return rc;
910 }
911
912 int
913 nameUIDPretty(
914         Syntax *syntax,
915         struct berval *val,
916         struct berval *out,
917         void *ctx )
918 {
919         assert( val != NULL );
920         assert( out != NULL );
921
922
923         Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
924
925         if( BER_BVISEMPTY( val ) ) {
926                 ber_dupbv_x( out, val, ctx );
927
928         } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
929                 return LDAP_INVALID_SYNTAX;
930
931         } else {
932                 int             rc;
933                 struct berval   dnval = *val;
934                 struct berval   uidval = BER_BVNULL;
935
936                 uidval.bv_val = strrchr( val->bv_val, '#' );
937                 if ( !BER_BVISNULL( &uidval ) ) {
938                         uidval.bv_val++;
939                         uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
940
941                         rc = bitStringValidate( NULL, &uidval );
942
943                         if ( rc == LDAP_SUCCESS ) {
944                                 ber_dupbv_x( &dnval, val, ctx );
945                                 dnval.bv_len -= uidval.bv_len + 1;
946                                 dnval.bv_val[dnval.bv_len] = '\0';
947
948                         } else {
949                                 BER_BVZERO( &uidval );
950                         }
951                 }
952
953                 rc = dnPretty( syntax, &dnval, out, ctx );
954                 if ( dnval.bv_val != val->bv_val ) {
955                         slap_sl_free( dnval.bv_val, ctx );
956                 }
957                 if( rc != LDAP_SUCCESS ) {
958                         return rc;
959                 }
960
961                 if( !BER_BVISNULL( &uidval ) ) {
962                         int     i, c, got1;
963                         char    *tmp;
964
965                         tmp = slap_sl_realloc( out->bv_val, out->bv_len 
966                                 + STRLENOF( "#" ) + uidval.bv_len + 1,
967                                 ctx );
968                         if( tmp == NULL ) {
969                                 ber_memfree_x( out->bv_val, ctx );
970                                 return LDAP_OTHER;
971                         }
972                         out->bv_val = tmp;
973                         out->bv_val[out->bv_len++] = '#';
974                         out->bv_val[out->bv_len++] = '\'';
975
976                         got1 = uidval.bv_len < sizeof("'0'B"); 
977                         for( i = 1; i < uidval.bv_len - 2; i++ ) {
978                                 c = uidval.bv_val[i];
979                                 switch(c) {
980                                         case '0':
981                                                 if( got1 ) out->bv_val[out->bv_len++] = c;
982                                                 break;
983                                         case '1':
984                                                 got1 = 1;
985                                                 out->bv_val[out->bv_len++] = c;
986                                                 break;
987                                 }
988                         }
989
990                         out->bv_val[out->bv_len++] = '\'';
991                         out->bv_val[out->bv_len++] = 'B';
992                         out->bv_val[out->bv_len] = '\0';
993                 }
994         }
995
996         Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
997
998         return LDAP_SUCCESS;
999 }
1000
1001 static int
1002 uniqueMemberNormalize(
1003         slap_mask_t usage,
1004         Syntax *syntax,
1005         MatchingRule *mr,
1006         struct berval *val,
1007         struct berval *normalized,
1008         void *ctx )
1009 {
1010         struct berval out;
1011         int rc;
1012
1013         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ));
1014
1015         ber_dupbv_x( &out, val, ctx );
1016         if ( BER_BVISEMPTY( &out ) ) {
1017                 *normalized = out;
1018
1019         } else {
1020                 struct berval uid = BER_BVNULL;
1021
1022                 uid.bv_val = strrchr( out.bv_val, '#' );
1023                 if ( !BER_BVISNULL( &uid ) ) {
1024                         uid.bv_val++;
1025                         uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1026
1027                         rc = bitStringValidate( NULL, &uid );
1028                         if ( rc == LDAP_SUCCESS ) {
1029                                 uid.bv_val[-1] = '\0';
1030                                 out.bv_len -= uid.bv_len + 1;
1031                         } else {
1032                                 BER_BVZERO( &uid );
1033                         }
1034                 }
1035
1036                 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1037
1038                 if( rc != LDAP_SUCCESS ) {
1039                         slap_sl_free( out.bv_val, ctx );
1040                         return LDAP_INVALID_SYNTAX;
1041                 }
1042
1043                 if( !BER_BVISNULL( &uid ) ) {
1044                         char    *tmp;
1045
1046                         tmp = ch_realloc( normalized->bv_val,
1047                                 normalized->bv_len + uid.bv_len
1048                                 + STRLENOF("#") + 1 );
1049                         if ( tmp == NULL ) {
1050                                 ber_memfree_x( normalized->bv_val, ctx );
1051                                 return LDAP_OTHER;
1052                         }
1053
1054                         normalized->bv_val = tmp;
1055
1056                         /* insert the separator */
1057                         normalized->bv_val[normalized->bv_len++] = '#';
1058
1059                         /* append the UID */
1060                         AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1061                                 uid.bv_val, uid.bv_len );
1062                         normalized->bv_len += uid.bv_len;
1063
1064                         /* terminate */
1065                         normalized->bv_val[normalized->bv_len] = '\0';
1066                 }
1067
1068                 slap_sl_free( out.bv_val, ctx );
1069         }
1070
1071         return LDAP_SUCCESS;
1072 }
1073
1074 static int
1075 uniqueMemberMatch(
1076         int *matchp,
1077         slap_mask_t flags,
1078         Syntax *syntax,
1079         MatchingRule *mr,
1080         struct berval *value,
1081         void *assertedValue )
1082 {
1083         int match;
1084         struct berval *asserted = (struct berval *) assertedValue;
1085         struct berval assertedDN = *asserted;
1086         struct berval assertedUID = BER_BVNULL;
1087         struct berval valueDN = *value;
1088         struct berval valueUID = BER_BVNULL;
1089         int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1090
1091         if ( !BER_BVISEMPTY( asserted ) ) {
1092                 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1093                 if ( !BER_BVISNULL( &assertedUID ) ) {
1094                         assertedUID.bv_val++;
1095                         assertedUID.bv_len = assertedDN.bv_len
1096                                 - ( assertedUID.bv_val - assertedDN.bv_val );
1097
1098                         if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1099                                 assertedDN.bv_len -= assertedUID.bv_len + 1;
1100
1101                         } else {
1102                                 BER_BVZERO( &assertedUID );
1103                         }
1104                 }
1105         }
1106
1107         if ( !BER_BVISEMPTY( value ) ) {
1108
1109                 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1110                 if ( !BER_BVISNULL( &valueUID ) ) {
1111                         valueUID.bv_val++;
1112                         valueUID.bv_len = valueDN.bv_len
1113                                 - ( valueUID.bv_val - valueDN.bv_val );
1114
1115                         if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1116                                 valueDN.bv_len -= valueUID.bv_len + 1;
1117
1118                         } else {
1119                                 BER_BVZERO( &valueUID );
1120                         }
1121                 }
1122         }
1123
1124         if( valueUID.bv_len && assertedUID.bv_len ) {
1125                 match = valueUID.bv_len - assertedUID.bv_len;
1126                 if ( match ) {
1127                         *matchp = match;
1128                         return LDAP_SUCCESS;
1129                 }
1130
1131                 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1132                 if( match ) {
1133                         *matchp = match;
1134                         return LDAP_SUCCESS;
1135                 }
1136
1137         } else if ( !approx && valueUID.bv_len ) {
1138                 match = -1;
1139                 *matchp = match;
1140                 return LDAP_SUCCESS;
1141
1142         } else if ( !approx && assertedUID.bv_len ) {
1143                 match = 1;
1144                 *matchp = match;
1145                 return LDAP_SUCCESS;
1146         }
1147
1148         return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1149 }
1150
1151 static int 
1152 uniqueMemberIndexer(
1153         slap_mask_t use,
1154         slap_mask_t flags,
1155         Syntax *syntax,
1156         MatchingRule *mr,
1157         struct berval *prefix,
1158         BerVarray values,
1159         BerVarray *keysp,
1160         void *ctx )
1161 {
1162         BerVarray dnvalues;
1163         int rc;
1164         int i;
1165         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1166                 /* just count them */                 
1167         }
1168         assert( i > 0 );
1169
1170         dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1171
1172         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1173                 struct berval assertedDN = values[i];
1174                 struct berval assertedUID = BER_BVNULL;
1175
1176                 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1177                         assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1178                         if ( !BER_BVISNULL( &assertedUID ) ) {
1179                                 assertedUID.bv_val++;
1180                                 assertedUID.bv_len = assertedDN.bv_len
1181                                         - ( assertedUID.bv_val - assertedDN.bv_val );
1182         
1183                                 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1184                                         assertedDN.bv_len -= assertedUID.bv_len + 1;
1185
1186                                 } else {
1187                                         BER_BVZERO( &assertedUID );
1188                                 }
1189                         }
1190                 }
1191
1192                 dnvalues[i] = assertedDN;
1193         }
1194         BER_BVZERO( &dnvalues[i] );
1195
1196         rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1197                 dnvalues, keysp, ctx );
1198
1199         slap_sl_free( dnvalues, ctx );
1200         return rc;
1201 }
1202
1203 static int 
1204 uniqueMemberFilter(
1205         slap_mask_t use,
1206         slap_mask_t flags,
1207         Syntax *syntax,
1208         MatchingRule *mr,
1209         struct berval *prefix,
1210         void * assertedValue,
1211         BerVarray *keysp,
1212         void *ctx )
1213 {
1214         struct berval *asserted = (struct berval *) assertedValue;
1215         struct berval assertedDN = *asserted;
1216         struct berval assertedUID = BER_BVNULL;
1217
1218         if ( !BER_BVISEMPTY( asserted ) ) {
1219                 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1220                 if ( !BER_BVISNULL( &assertedUID ) ) {
1221                         assertedUID.bv_val++;
1222                         assertedUID.bv_len = assertedDN.bv_len
1223                                 - ( assertedUID.bv_val - assertedDN.bv_val );
1224
1225                         if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1226                                 assertedDN.bv_len -= assertedUID.bv_len + 1;
1227
1228                         } else {
1229                                 BER_BVZERO( &assertedUID );
1230                         }
1231                 }
1232         }
1233
1234         return octetStringFilter( use, flags, syntax, mr, prefix,
1235                 &assertedDN, keysp, ctx );
1236 }
1237
1238
1239 /*
1240  * Handling boolean syntax and matching is quite rigid.
1241  * A more flexible approach would be to allow a variety
1242  * of strings to be normalized and prettied into TRUE
1243  * and FALSE.
1244  */
1245 static int
1246 booleanValidate(
1247         Syntax *syntax,
1248         struct berval *in )
1249 {
1250         /* very unforgiving validation, requires no normalization
1251          * before simplistic matching
1252          */
1253
1254         if( in->bv_len == 4 ) {
1255                 if( bvmatch( in, &slap_true_bv ) ) {
1256                         return LDAP_SUCCESS;
1257                 }
1258         } else if( in->bv_len == 5 ) {
1259                 if( bvmatch( in, &slap_false_bv ) ) {
1260                         return LDAP_SUCCESS;
1261                 }
1262         }
1263
1264         return LDAP_INVALID_SYNTAX;
1265 }
1266
1267 static int
1268 booleanMatch(
1269         int *matchp,
1270         slap_mask_t flags,
1271         Syntax *syntax,
1272         MatchingRule *mr,
1273         struct berval *value,
1274         void *assertedValue )
1275 {
1276         /* simplistic matching allowed by rigid validation */
1277         struct berval *asserted = (struct berval *) assertedValue;
1278         *matchp = value->bv_len != asserted->bv_len;
1279         return LDAP_SUCCESS;
1280 }
1281
1282 /*-------------------------------------------------------------------
1283 LDAP/X.500 string syntax / matching rules have a few oddities.  This
1284 comment attempts to detail how slapd(8) treats them.
1285
1286 Summary:
1287   StringSyntax          X.500   LDAP    Matching/Comments
1288   DirectoryString       CHOICE  UTF8    i/e + ignore insignificant spaces
1289   PrintableString       subset  subset  i/e + ignore insignificant spaces
1290   PrintableString       subset  subset  i/e + ignore insignificant spaces
1291   NumericString         subset  subset  ignore all spaces
1292   IA5String                     ASCII   ASCII   i/e + ignore insignificant spaces
1293   TeletexString         T.61    T.61    i/e + ignore insignificant spaces
1294
1295   TelephoneNumber       subset  subset  i + ignore all spaces and "-"
1296
1297   See draft-ietf-ldapbis-strpro for details (once published).
1298
1299
1300 Directory String -
1301   In X.500(93), a directory string can be either a PrintableString,
1302   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1303   In later versions, more CHOICEs were added.  In all cases the string
1304   must be non-empty.
1305
1306   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1307   A directory string cannot be zero length.
1308
1309   For matching, there are both case ignore and exact rules.  Both
1310   also require that "insignificant" spaces be ignored.
1311         spaces before the first non-space are ignored;
1312         spaces after the last non-space are ignored;
1313         spaces after a space are ignored.
1314   Note: by these rules (and as clarified in X.520), a string of only
1315   spaces is to be treated as if held one space, not empty (which
1316   would be a syntax error).
1317
1318 NumericString
1319   In ASN.1, numeric string is just a string of digits and spaces
1320   and could be empty.  However, in X.500, all attribute values of
1321   numeric string carry a non-empty constraint.  For example:
1322
1323         internationalISDNNumber ATTRIBUTE ::= {
1324                 WITH SYNTAX InternationalISDNNumber
1325                 EQUALITY MATCHING RULE numericStringMatch
1326                 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1327                 ID id-at-internationalISDNNumber }
1328         InternationalISDNNumber ::=
1329             NumericString (SIZE(1..ub-international-isdn-number))
1330
1331   Unforunately, some assertion values are don't carry the same
1332   constraint (but its unclear how such an assertion could ever
1333   be true). In LDAP, there is one syntax (numericString) not two
1334   (numericString with constraint, numericString without constraint).
1335   This should be treated as numericString with non-empty constraint.
1336   Note that while someone may have no ISDN number, there are no ISDN
1337   numbers which are zero length.
1338
1339   In matching, spaces are ignored.
1340
1341 PrintableString
1342   In ASN.1, Printable string is just a string of printable characters
1343   and can be empty.  In X.500, semantics much like NumericString (see
1344   serialNumber for a like example) excepting uses insignificant space
1345   handling instead of ignore all spaces.  
1346
1347 IA5String
1348   Basically same as PrintableString.  There are no examples in X.500,
1349   but same logic applies.  So we require them to be non-empty as
1350   well.
1351
1352 -------------------------------------------------------------------*/
1353
1354 static int
1355 UTF8StringValidate(
1356         Syntax *syntax,
1357         struct berval *in )
1358 {
1359         ber_len_t count;
1360         int len;
1361         unsigned char *u = (unsigned char *)in->bv_val;
1362
1363         if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1364                 /* directory strings cannot be empty */
1365                 return LDAP_INVALID_SYNTAX;
1366         }
1367
1368         for( count = in->bv_len; count > 0; count -= len, u += len ) {
1369                 /* get the length indicated by the first byte */
1370                 len = LDAP_UTF8_CHARLEN2( u, len );
1371
1372                 /* very basic checks */
1373                 switch( len ) {
1374                         case 6:
1375                                 if( (u[5] & 0xC0) != 0x80 ) {
1376                                         return LDAP_INVALID_SYNTAX;
1377                                 }
1378                         case 5:
1379                                 if( (u[4] & 0xC0) != 0x80 ) {
1380                                         return LDAP_INVALID_SYNTAX;
1381                                 }
1382                         case 4:
1383                                 if( (u[3] & 0xC0) != 0x80 ) {
1384                                         return LDAP_INVALID_SYNTAX;
1385                                 }
1386                         case 3:
1387                                 if( (u[2] & 0xC0 )!= 0x80 ) {
1388                                         return LDAP_INVALID_SYNTAX;
1389                                 }
1390                         case 2:
1391                                 if( (u[1] & 0xC0) != 0x80 ) {
1392                                         return LDAP_INVALID_SYNTAX;
1393                                 }
1394                         case 1:
1395                                 /* CHARLEN already validated it */
1396                                 break;
1397                         default:
1398                                 return LDAP_INVALID_SYNTAX;
1399                 }
1400
1401                 /* make sure len corresponds with the offset
1402                         to the next character */
1403                 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1404         }
1405
1406         if( count != 0 ) {
1407                 return LDAP_INVALID_SYNTAX;
1408         }
1409
1410         return LDAP_SUCCESS;
1411 }
1412
1413 static int
1414 UTF8StringNormalize(
1415         slap_mask_t use,
1416         Syntax *syntax,
1417         MatchingRule *mr,
1418         struct berval *val,
1419         struct berval *normalized,
1420         void *ctx )
1421 {
1422         struct berval tmp, nvalue;
1423         int flags;
1424         int i, wasspace;
1425
1426         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
1427
1428         if( BER_BVISNULL( val ) ) {
1429                 /* assume we're dealing with a syntax (e.g., UTF8String)
1430                  * which allows empty strings
1431                  */
1432                 BER_BVZERO( normalized );
1433                 return LDAP_SUCCESS;
1434         }
1435
1436         flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1437                 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1438         flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1439                 ? LDAP_UTF8_APPROX : 0;
1440
1441         val = UTF8bvnormalize( val, &tmp, flags, ctx );
1442         if( val == NULL ) {
1443                 return LDAP_OTHER;
1444         }
1445         
1446         /* collapse spaces (in place) */
1447         nvalue.bv_len = 0;
1448         nvalue.bv_val = tmp.bv_val;
1449
1450         /* trim leading spaces? */
1451         wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1452                 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1453
1454         for( i = 0; i < tmp.bv_len; i++) {
1455                 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1456                         if( wasspace++ == 0 ) {
1457                                 /* trim repeated spaces */
1458                                 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1459                         }
1460                 } else {
1461                         wasspace = 0;
1462                         nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1463                 }
1464         }
1465
1466         if( !BER_BVISEMPTY( &nvalue ) ) {
1467                 /* trim trailing space? */
1468                 if( wasspace && (
1469                         (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1470                         ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1471                 {
1472                         --nvalue.bv_len;
1473                 }
1474                 nvalue.bv_val[nvalue.bv_len] = '\0';
1475
1476         } else {
1477                 /* string of all spaces is treated as one space */
1478                 nvalue.bv_val[0] = ' ';
1479                 nvalue.bv_val[1] = '\0';
1480                 nvalue.bv_len = 1;
1481         }
1482
1483         *normalized = nvalue;
1484         return LDAP_SUCCESS;
1485 }
1486
1487 static int
1488 directoryStringSubstringsMatch(
1489         int *matchp,
1490         slap_mask_t flags,
1491         Syntax *syntax,
1492         MatchingRule *mr,
1493         struct berval *value,
1494         void *assertedValue )
1495 {
1496         int match = 0;
1497         SubstringsAssertion *sub = assertedValue;
1498         struct berval left = *value;
1499         int i;
1500         int priorspace=0;
1501
1502         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1503                 if ( sub->sa_initial.bv_len > left.bv_len ) {
1504                         /* not enough left */
1505                         match = 1;
1506                         goto done;
1507                 }
1508
1509                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1510                         sub->sa_initial.bv_len );
1511
1512                 if ( match != 0 ) {
1513                         goto done;
1514                 }
1515
1516                 left.bv_val += sub->sa_initial.bv_len;
1517                 left.bv_len -= sub->sa_initial.bv_len;
1518
1519                 priorspace = ASCII_SPACE(
1520                         sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1521         }
1522
1523         if ( sub->sa_any ) {
1524                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1525                         ber_len_t idx;
1526                         char *p;
1527
1528                         if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] ) 
1529                                 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1530                         { 
1531                                 /* allow next space to match */
1532                                 left.bv_val--;
1533                                 left.bv_len++;
1534                         }
1535                         priorspace=0;
1536
1537 retry:
1538                         if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1539                                 continue;
1540                         }
1541
1542                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1543                                 /* not enough left */
1544                                 match = 1;
1545                                 goto done;
1546                         }
1547
1548                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1549
1550                         if( p == NULL ) {
1551                                 match = 1;
1552                                 goto done;
1553                         }
1554
1555                         idx = p - left.bv_val;
1556
1557                         if ( idx >= left.bv_len ) {
1558                                 /* this shouldn't happen */
1559                                 return LDAP_OTHER;
1560                         }
1561
1562                         left.bv_val = p;
1563                         left.bv_len -= idx;
1564
1565                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1566                                 /* not enough left */
1567                                 match = 1;
1568                                 goto done;
1569                         }
1570
1571                         match = memcmp( left.bv_val,
1572                                 sub->sa_any[i].bv_val,
1573                                 sub->sa_any[i].bv_len );
1574
1575                         if ( match != 0 ) {
1576                                 left.bv_val++;
1577                                 left.bv_len--;
1578                                 goto retry;
1579                         }
1580
1581                         left.bv_val += sub->sa_any[i].bv_len;
1582                         left.bv_len -= sub->sa_any[i].bv_len;
1583
1584                         priorspace = ASCII_SPACE(
1585                                 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1586                 }
1587         }
1588
1589         if ( !BER_BVISNULL( &sub->sa_final ) ) {
1590                 if( priorspace && !BER_BVISEMPTY( &sub->sa_final ) 
1591                         && ASCII_SPACE( sub->sa_final.bv_val[0] ))
1592                 { 
1593                         /* allow next space to match */
1594                         left.bv_val--;
1595                         left.bv_len++;
1596                 }
1597
1598                 if ( sub->sa_final.bv_len > left.bv_len ) {
1599                         /* not enough left */
1600                         match = 1;
1601                         goto done;
1602                 }
1603
1604                 match = memcmp( sub->sa_final.bv_val,
1605                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1606                         sub->sa_final.bv_len );
1607
1608                 if ( match != 0 ) {
1609                         goto done;
1610                 }
1611         }
1612
1613 done:
1614         *matchp = match;
1615         return LDAP_SUCCESS;
1616 }
1617
1618 #if defined(SLAPD_APPROX_INITIALS)
1619 #       define SLAPD_APPROX_DELIMITER "._ "
1620 #       define SLAPD_APPROX_WORDLEN 2
1621 #else
1622 #       define SLAPD_APPROX_DELIMITER " "
1623 #       define SLAPD_APPROX_WORDLEN 1
1624 #endif
1625
1626 static int
1627 approxMatch(
1628         int *matchp,
1629         slap_mask_t flags,
1630         Syntax *syntax,
1631         MatchingRule *mr,
1632         struct berval *value,
1633         void *assertedValue )
1634 {
1635         struct berval *nval, *assertv;
1636         char *val, **values, **words, *c;
1637         int i, count, len, nextchunk=0, nextavail=0;
1638
1639         /* Yes, this is necessary */
1640         nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
1641         if( nval == NULL ) {
1642                 *matchp = 1;
1643                 return LDAP_SUCCESS;
1644         }
1645
1646         /* Yes, this is necessary */
1647         assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1648                 NULL, LDAP_UTF8_APPROX, NULL );
1649         if( assertv == NULL ) {
1650                 ber_bvfree( nval );
1651                 *matchp = 1;
1652                 return LDAP_SUCCESS;
1653         }
1654
1655         /* Isolate how many words there are */
1656         for ( c = nval->bv_val, count = 1; *c; c++ ) {
1657                 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1658                 if ( c == NULL ) break;
1659                 *c = '\0';
1660                 count++;
1661         }
1662
1663         /* Get a phonetic copy of each word */
1664         words = (char **)ch_malloc( count * sizeof(char *) );
1665         values = (char **)ch_malloc( count * sizeof(char *) );
1666         for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
1667                 words[i] = c;
1668                 values[i] = phonetic(c);
1669         }
1670
1671         /* Work through the asserted value's words, to see if at least some
1672            of the words are there, in the same order. */
1673         len = 0;
1674         while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1675                 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1676                 if( len == 0 ) {
1677                         nextchunk++;
1678                         continue;
1679                 }
1680 #if defined(SLAPD_APPROX_INITIALS)
1681                 else if( len == 1 ) {
1682                         /* Single letter words need to at least match one word's initial */
1683                         for( i=nextavail; i<count; i++ )
1684                                 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1685                                         nextavail=i+1;
1686                                         break;
1687                                 }
1688                 }
1689 #endif
1690                 else {
1691                         /* Isolate the next word in the asserted value and phonetic it */
1692                         assertv->bv_val[nextchunk+len] = '\0';
1693                         val = phonetic( assertv->bv_val + nextchunk );
1694
1695                         /* See if this phonetic chunk is in the remaining words of *value */
1696                         for( i=nextavail; i<count; i++ ){
1697                                 if( !strcmp( val, values[i] ) ){
1698                                         nextavail = i+1;
1699                                         break;
1700                                 }
1701                         }
1702                         ch_free( val );
1703                 }
1704
1705                 /* This chunk in the asserted value was NOT within the *value. */
1706                 if( i >= count ) {
1707                         nextavail=-1;
1708                         break;
1709                 }
1710
1711                 /* Go on to the next word in the asserted value */
1712                 nextchunk += len+1;
1713         }
1714
1715         /* If some of the words were seen, call it a match */
1716         if( nextavail > 0 ) {
1717                 *matchp = 0;
1718         }
1719         else {
1720                 *matchp = 1;
1721         }
1722
1723         /* Cleanup allocs */
1724         ber_bvfree( assertv );
1725         for( i=0; i<count; i++ ) {
1726                 ch_free( values[i] );
1727         }
1728         ch_free( values );
1729         ch_free( words );
1730         ber_bvfree( nval );
1731
1732         return LDAP_SUCCESS;
1733 }
1734
1735 static int 
1736 approxIndexer(
1737         slap_mask_t use,
1738         slap_mask_t flags,
1739         Syntax *syntax,
1740         MatchingRule *mr,
1741         struct berval *prefix,
1742         BerVarray values,
1743         BerVarray *keysp,
1744         void *ctx )
1745 {
1746         char *c;
1747         int i,j, len, wordcount, keycount=0;
1748         struct berval *newkeys;
1749         BerVarray keys=NULL;
1750
1751         for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
1752                 struct berval val = BER_BVNULL;
1753                 /* Yes, this is necessary */
1754                 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
1755                 assert( !BER_BVISNULL( &val ) );
1756
1757                 /* Isolate how many words there are. There will be a key for each */
1758                 for( wordcount = 0, c = val.bv_val; *c; c++) {
1759                         len = strcspn(c, SLAPD_APPROX_DELIMITER);
1760                         if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1761                         c+= len;
1762                         if (*c == '\0') break;
1763                         *c = '\0';
1764                 }
1765
1766                 /* Allocate/increase storage to account for new keys */
1767                 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
1768                         * sizeof(struct berval) );
1769                 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1770                 if( keys ) ch_free( keys );
1771                 keys = newkeys;
1772
1773                 /* Get a phonetic copy of each word */
1774                 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1775                         len = strlen( c );
1776                         if( len < SLAPD_APPROX_WORDLEN ) continue;
1777                         ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1778                         keycount++;
1779                         i++;
1780                 }
1781
1782                 ber_memfree( val.bv_val );
1783         }
1784         BER_BVZERO( &keys[keycount] );
1785         *keysp = keys;
1786
1787         return LDAP_SUCCESS;
1788 }
1789
1790 static int 
1791 approxFilter(
1792         slap_mask_t use,
1793         slap_mask_t flags,
1794         Syntax *syntax,
1795         MatchingRule *mr,
1796         struct berval *prefix,
1797         void * assertedValue,
1798         BerVarray *keysp,
1799         void *ctx )
1800 {
1801         char *c;
1802         int i, count, len;
1803         struct berval *val;
1804         BerVarray keys;
1805
1806         /* Yes, this is necessary */
1807         val = UTF8bvnormalize( ((struct berval *)assertedValue),
1808                 NULL, LDAP_UTF8_APPROX, NULL );
1809         if( val == NULL || BER_BVISNULL( val ) ) {
1810                 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1811                 BER_BVZERO( &keys[0] );
1812                 *keysp = keys;
1813                 ber_bvfree( val );
1814                 return LDAP_SUCCESS;
1815         }
1816
1817         /* Isolate how many words there are. There will be a key for each */
1818         for( count = 0,c = val->bv_val; *c; c++) {
1819                 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1820                 if( len >= SLAPD_APPROX_WORDLEN ) count++;
1821                 c+= len;
1822                 if (*c == '\0') break;
1823                 *c = '\0';
1824         }
1825
1826         /* Allocate storage for new keys */
1827         keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1828
1829         /* Get a phonetic copy of each word */
1830         for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1831                 len = strlen(c);
1832                 if( len < SLAPD_APPROX_WORDLEN ) continue;
1833                 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1834                 i++;
1835         }
1836
1837         ber_bvfree( val );
1838
1839         BER_BVZERO( &keys[count] );
1840         *keysp = keys;
1841
1842         return LDAP_SUCCESS;
1843 }
1844
1845 /* Remove all spaces and '-' characters */
1846 static int
1847 telephoneNumberNormalize(
1848         slap_mask_t usage,
1849         Syntax *syntax,
1850         MatchingRule *mr,
1851         struct berval *val,
1852         struct berval *normalized,
1853         void *ctx )
1854 {
1855         char *p, *q;
1856
1857         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ));
1858
1859         /* validator should have refused an empty string */
1860         assert( !BER_BVISEMPTY( val ) );
1861
1862         q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
1863
1864         for( p = val->bv_val; *p; p++ ) {
1865                 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1866                         *q++ = *p;
1867                 }
1868         }
1869         *q = '\0';
1870
1871         normalized->bv_len = q - normalized->bv_val;
1872
1873         if( BER_BVISEMPTY( normalized ) ) {
1874                 slap_sl_free( normalized->bv_val, ctx );
1875                 BER_BVZERO( normalized );
1876                 return LDAP_INVALID_SYNTAX;
1877         }
1878
1879         return LDAP_SUCCESS;
1880 }
1881
1882 int
1883 numericoidValidate(
1884         Syntax *syntax,
1885         struct berval *in )
1886 {
1887         struct berval val = *in;
1888
1889         if( BER_BVISEMPTY( &val ) ) {
1890                 /* disallow empty strings */
1891                 return LDAP_INVALID_SYNTAX;
1892         }
1893
1894         while( OID_LEADCHAR( val.bv_val[0] ) ) {
1895                 if ( val.bv_len == 1 ) {
1896                         return LDAP_SUCCESS;
1897                 }
1898
1899                 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
1900                         break;
1901                 }
1902
1903                 val.bv_val++;
1904                 val.bv_len--;
1905
1906                 while ( OID_LEADCHAR( val.bv_val[0] )) {
1907                         val.bv_val++;
1908                         val.bv_len--;
1909
1910                         if ( val.bv_len == 0 ) {
1911                                 return LDAP_SUCCESS;
1912                         }
1913                 }
1914
1915                 if( !OID_SEPARATOR( val.bv_val[0] )) {
1916                         break;
1917                 }
1918
1919                 val.bv_val++;
1920                 val.bv_len--;
1921         }
1922
1923         return LDAP_INVALID_SYNTAX;
1924 }
1925
1926 static int
1927 integerValidate(
1928         Syntax *syntax,
1929         struct berval *in )
1930 {
1931         ber_len_t i;
1932         struct berval val = *in;
1933
1934         if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
1935
1936         if ( val.bv_val[0] == '-' ) {
1937                 val.bv_len--;
1938                 val.bv_val++;
1939
1940                 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
1941                         return LDAP_INVALID_SYNTAX;
1942                 }
1943
1944                 if( val.bv_val[0] == '0' ) { /* "-0" */
1945                         return LDAP_INVALID_SYNTAX;
1946                 }
1947
1948         } else if ( val.bv_val[0] == '0' ) {
1949                 if( val.bv_len > 1 ) { /* "0<more>" */
1950                         return LDAP_INVALID_SYNTAX;
1951                 }
1952
1953                 return LDAP_SUCCESS;
1954         }
1955
1956         for( i=0; i < val.bv_len; i++ ) {
1957                 if( !ASCII_DIGIT(val.bv_val[i]) ) {
1958                         return LDAP_INVALID_SYNTAX;
1959                 }
1960         }
1961
1962         return LDAP_SUCCESS;
1963 }
1964
1965 static int
1966 integerMatch(
1967         int *matchp,
1968         slap_mask_t flags,
1969         Syntax *syntax,
1970         MatchingRule *mr,
1971         struct berval *value,
1972         void *assertedValue )
1973 {
1974         struct berval *asserted = (struct berval *) assertedValue;
1975         int vsign = 1, asign = 1;       /* default sign = '+' */
1976         struct berval v, a;
1977         int match;
1978
1979         v = *value;
1980         if( v.bv_val[0] == '-' ) {
1981                 vsign = -1;
1982                 v.bv_val++;
1983                 v.bv_len--;
1984         }
1985
1986         if( BER_BVISEMPTY( &v ) ) vsign = 0;
1987
1988         a = *asserted;
1989         if( a.bv_val[0] == '-' ) {
1990                 asign = -1;
1991                 a.bv_val++;
1992                 a.bv_len--;
1993         }
1994
1995         if( BER_BVISEMPTY( &a ) ) vsign = 0;
1996
1997         match = vsign - asign;
1998         if( match == 0 ) {
1999                 match = ( v.bv_len != a.bv_len
2000                         ? ( v.bv_len < a.bv_len ? -1 : 1 )
2001                         : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2002                 if( vsign < 0 ) match = -match;
2003         }
2004
2005         *matchp = match;
2006         return LDAP_SUCCESS;
2007 }
2008         
2009 static int
2010 countryStringValidate(
2011         Syntax *syntax,
2012         struct berval *val )
2013 {
2014         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2015
2016         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2017                 return LDAP_INVALID_SYNTAX;
2018         }
2019         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2020                 return LDAP_INVALID_SYNTAX;
2021         }
2022
2023         return LDAP_SUCCESS;
2024 }
2025
2026 static int
2027 printableStringValidate(
2028         Syntax *syntax,
2029         struct berval *val )
2030 {
2031         ber_len_t i;
2032
2033         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2034
2035         for(i=0; i < val->bv_len; i++) {
2036                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2037                         return LDAP_INVALID_SYNTAX;
2038                 }
2039         }
2040
2041         return LDAP_SUCCESS;
2042 }
2043
2044 static int
2045 printablesStringValidate(
2046         Syntax *syntax,
2047         struct berval *val )
2048 {
2049         ber_len_t i, len;
2050
2051         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2052
2053         for(i=0,len=0; i < val->bv_len; i++) {
2054                 int c = val->bv_val[i];
2055
2056                 if( c == '$' ) {
2057                         if( len == 0 ) {
2058                                 return LDAP_INVALID_SYNTAX;
2059                         }
2060                         len = 0;
2061
2062                 } else if ( SLAP_PRINTABLE(c) ) {
2063                         len++;
2064                 } else {
2065                         return LDAP_INVALID_SYNTAX;
2066                 }
2067         }
2068
2069         if( len == 0 ) {
2070                 return LDAP_INVALID_SYNTAX;
2071         }
2072
2073         return LDAP_SUCCESS;
2074 }
2075
2076 static int
2077 IA5StringValidate(
2078         Syntax *syntax,
2079         struct berval *val )
2080 {
2081         ber_len_t i;
2082
2083         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2084
2085         for(i=0; i < val->bv_len; i++) {
2086                 if( !LDAP_ASCII(val->bv_val[i]) ) {
2087                         return LDAP_INVALID_SYNTAX;
2088                 }
2089         }
2090
2091         return LDAP_SUCCESS;
2092 }
2093
2094 static int
2095 IA5StringNormalize(
2096         slap_mask_t use,
2097         Syntax *syntax,
2098         MatchingRule *mr,
2099         struct berval *val,
2100         struct berval *normalized,
2101         void *ctx )
2102 {
2103         char *p, *q;
2104         int casefold = !SLAP_MR_ASSOCIATED(mr, slap_schema.si_mr_caseExactIA5Match);
2105
2106         assert( !BER_BVISEMPTY( val ) );
2107
2108         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
2109
2110         p = val->bv_val;
2111
2112         /* Ignore initial whitespace */
2113         while ( ASCII_SPACE( *p ) ) p++;
2114
2115         normalized->bv_val = ber_strdup_x( p, ctx );
2116         p = q = normalized->bv_val;
2117
2118         while ( *p ) {
2119                 if ( ASCII_SPACE( *p ) ) {
2120                         *q++ = *p++;
2121
2122                         /* Ignore the extra whitespace */
2123                         while ( ASCII_SPACE( *p ) ) {
2124                                 p++;
2125                         }
2126
2127                 } else if ( casefold ) {
2128                         /* Most IA5 rules require casefolding */
2129                         *q++ = TOLOWER(*p); p++;
2130
2131                 } else {
2132                         *q++ = *p++;
2133                 }
2134         }
2135
2136         assert( normalized->bv_val <= p );
2137         assert( q <= p );
2138
2139         /*
2140          * If the string ended in space, backup the pointer one
2141          * position.  One is enough because the above loop collapsed
2142          * all whitespace to a single space.
2143          */
2144         if ( ASCII_SPACE( q[-1] ) ) --q;
2145
2146         /* null terminate */
2147         *q = '\0';
2148
2149         normalized->bv_len = q - normalized->bv_val;
2150         if( BER_BVISEMPTY( normalized ) ) {
2151                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2152                 normalized->bv_val[0] = ' ';
2153                 normalized->bv_val[1] = '\0';
2154                 normalized->bv_len = 1;
2155         }
2156
2157         return LDAP_SUCCESS;
2158 }
2159
2160 static int
2161 UUIDValidate(
2162         Syntax *syntax,
2163         struct berval *in )
2164 {
2165         int i;
2166         if( in->bv_len != 36 ) {
2167                 return LDAP_INVALID_SYNTAX;
2168         }
2169
2170         for( i=0; i<36; i++ ) {
2171                 switch(i) {
2172                         case 8:
2173                         case 13:
2174                         case 18:
2175                         case 23:
2176                                 if( in->bv_val[i] != '-' ) {
2177                                         return LDAP_INVALID_SYNTAX;
2178                                 }
2179                                 break;
2180                         default:
2181                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2182                                         return LDAP_INVALID_SYNTAX;
2183                                 }
2184                 }
2185         }
2186         
2187         return LDAP_SUCCESS;
2188 }
2189
2190 static int
2191 UUIDNormalize(
2192         slap_mask_t usage,
2193         Syntax *syntax,
2194         MatchingRule *mr,
2195         struct berval *val,
2196         struct berval *normalized,
2197         void *ctx )
2198 {
2199         unsigned char octet = '\0';
2200         int i;
2201         int j;
2202         normalized->bv_len = 16;
2203         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2204
2205         for( i=0, j=0; i<36; i++ ) {
2206                 unsigned char nibble;
2207                 if( val->bv_val[i] == '-' ) {
2208                         continue;
2209
2210                 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2211                         nibble = val->bv_val[i] - '0';
2212
2213                 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2214                         nibble = val->bv_val[i] - ('a'-10);
2215
2216                 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2217                         nibble = val->bv_val[i] - ('A'-10);
2218
2219                 } else {
2220                         slap_sl_free( normalized->bv_val, ctx );
2221                         return LDAP_INVALID_SYNTAX;
2222                 }
2223
2224                 if( j & 1 ) {
2225                         octet |= nibble;
2226                         normalized->bv_val[j>>1] = octet;
2227                 } else {
2228                         octet = nibble << 4;
2229                 }
2230                 j++;
2231         }
2232
2233         normalized->bv_val[normalized->bv_len] = 0;
2234         return LDAP_SUCCESS;
2235 }
2236
2237
2238
2239 static int
2240 numericStringValidate(
2241         Syntax *syntax,
2242         struct berval *in )
2243 {
2244         ber_len_t i;
2245
2246         if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2247
2248         for(i=0; i < in->bv_len; i++) {
2249                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2250                         return LDAP_INVALID_SYNTAX;
2251                 }
2252         }
2253
2254         return LDAP_SUCCESS;
2255 }
2256
2257 static int
2258 numericStringNormalize(
2259         slap_mask_t usage,
2260         Syntax *syntax,
2261         MatchingRule *mr,
2262         struct berval *val,
2263         struct berval *normalized,
2264         void *ctx )
2265 {
2266         /* removal all spaces */
2267         char *p, *q;
2268
2269         assert( !BER_BVISEMPTY( val ) );
2270
2271         normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2272
2273         p = val->bv_val;
2274         q = normalized->bv_val;
2275
2276         while ( *p ) {
2277                 if ( ASCII_SPACE( *p ) ) {
2278                         /* Ignore whitespace */
2279                         p++;
2280                 } else {
2281                         *q++ = *p++;
2282                 }
2283         }
2284
2285         /* we should have copied no more then is in val */
2286         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2287
2288         /* null terminate */
2289         *q = '\0';
2290
2291         normalized->bv_len = q - normalized->bv_val;
2292
2293         if( BER_BVISEMPTY( normalized ) ) {
2294                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2295                 normalized->bv_val[0] = ' ';
2296                 normalized->bv_val[1] = '\0';
2297                 normalized->bv_len = 1;
2298         }
2299
2300         return LDAP_SUCCESS;
2301 }
2302
2303 /*
2304  * Integer conversion macros that will use the largest available
2305  * type.
2306  */
2307 #if defined(HAVE_STRTOLL) && defined(LLONG_MAX) \
2308         && defined(LLONG_MIN) && defined(HAVE_LONG_LONG)
2309 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
2310 # define SLAP_LONG_MAX       LLONG_MAX
2311 # define SLAP_LONG_MIN       LLONG_MIN
2312 # define SLAP_LONG           long long
2313 #else
2314 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
2315 # define SLAP_LONG_MAX       LONG_MAX
2316 # define SLAP_LONG_MIN       LONG_MIN
2317 # define SLAP_LONG           long
2318 #endif /* HAVE_STRTOLL ... */
2319
2320 static int
2321 integerBitAndMatch(
2322         int *matchp,
2323         slap_mask_t flags,
2324         Syntax *syntax,
2325         MatchingRule *mr,
2326         struct berval *value,
2327         void *assertedValue )
2328 {
2329         SLAP_LONG lValue, lAssertedValue;
2330
2331         /* safe to assume integers are NUL terminated? */
2332         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2333         if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX) &&
2334                 errno == ERANGE )
2335         {
2336                 return LDAP_CONSTRAINT_VIOLATION;
2337         }
2338
2339         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2340                 NULL, 10);
2341         if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX ) &&
2342                 errno == ERANGE )
2343         {
2344                 return LDAP_CONSTRAINT_VIOLATION;
2345         }
2346
2347         *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2348         return LDAP_SUCCESS;
2349 }
2350
2351 static int
2352 integerBitOrMatch(
2353         int *matchp,
2354         slap_mask_t flags,
2355         Syntax *syntax,
2356         MatchingRule *mr,
2357         struct berval *value,
2358         void *assertedValue )
2359 {
2360         SLAP_LONG lValue, lAssertedValue;
2361
2362         /* safe to assume integers are NUL terminated? */
2363         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2364         if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX ) &&
2365                 errno == ERANGE )
2366         {
2367                 return LDAP_CONSTRAINT_VIOLATION;
2368         }
2369
2370         lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2371                 NULL, 10);
2372         if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX ) &&
2373                 errno == ERANGE )
2374         {
2375                 return LDAP_CONSTRAINT_VIOLATION;
2376         }
2377
2378         *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2379         return LDAP_SUCCESS;
2380 }
2381
2382 static int
2383 serialNumberAndIssuerValidate(
2384         Syntax *syntax,
2385         struct berval *in )
2386 {
2387         int rc;
2388         ber_len_t n;
2389         struct berval sn, i;
2390         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2391
2392         i.bv_val = ber_bvchr( in, '$' );
2393         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2394
2395         sn.bv_val = in->bv_val;
2396         sn.bv_len = i.bv_val - in->bv_val;
2397
2398         i.bv_val++;
2399         i.bv_len = in->bv_len - (sn.bv_len + 1);
2400
2401         /* validate serial number (strict for now) */
2402         for( n=0; n < sn.bv_len; n++ ) {
2403                 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2404         }
2405
2406         /* validate DN */
2407         rc = dnValidate( NULL, &i );
2408         if( rc ) return LDAP_INVALID_SYNTAX;
2409
2410         return LDAP_SUCCESS;
2411 }
2412
2413 int
2414 serialNumberAndIssuerPretty(
2415         Syntax *syntax,
2416         struct berval *val,
2417         struct berval *out,
2418         void *ctx )
2419 {
2420         int rc;
2421         ber_len_t n;
2422         struct berval sn, i, newi;
2423
2424         assert( val != NULL );
2425         assert( out != NULL );
2426
2427         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
2428                 val->bv_val, 0, 0 );
2429
2430         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2431
2432         i.bv_val = ber_bvchr( val, '$' );
2433         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2434
2435         sn.bv_val = val->bv_val;
2436         sn.bv_len = i.bv_val - val->bv_val;
2437
2438         i.bv_val++;
2439         i.bv_len = val->bv_len - (sn.bv_len + 1);
2440
2441         /* eat leading zeros */
2442         for( n=0; n < (sn.bv_len-1); n++ ) {
2443                 if( sn.bv_val[n] != '0' ) break;
2444         }
2445         sn.bv_val += n;
2446         sn.bv_len -= n;
2447
2448         for( n=0; n < sn.bv_len; n++ ) {
2449                 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2450         }
2451
2452         /* pretty DN */
2453         rc = dnPretty( syntax, &i, &newi, ctx );
2454         if( rc ) return LDAP_INVALID_SYNTAX;
2455
2456         /* make room from sn + "$" */
2457         out->bv_len = sn.bv_len + newi.bv_len + 1;
2458         out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2459
2460         if( out->bv_val == NULL ) {
2461                 out->bv_len = 0;
2462                 slap_sl_free( newi.bv_val, ctx );
2463                 return LDAP_OTHER;
2464         }
2465
2466         /* push issuer over */
2467         AC_MEMCPY( &out->bv_val[sn.bv_len+1], out->bv_val, newi.bv_len );
2468         /* insert sn and "$" */
2469         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2470         out->bv_val[sn.bv_len] = '$';
2471         /* terminate */
2472         out->bv_val[out->bv_len] = '\0';
2473
2474         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
2475                 out->bv_val, 0, 0 );
2476
2477         return LDAP_SUCCESS;
2478 }
2479
2480 /*
2481  * This routine is called by certificateExactNormalize when
2482  * certificateExactNormalize receives a search string instead of
2483  * a certificate. This routine checks if the search value is valid
2484  * and then returns the normalized value
2485  */
2486 static int
2487 serialNumberAndIssuerNormalize(
2488         slap_mask_t usage,
2489         Syntax *syntax,
2490         MatchingRule *mr,
2491         struct berval *val,
2492         struct berval *out,
2493         void *ctx )
2494 {
2495         int rc;
2496         ber_len_t n;
2497         struct berval sn, i, newi;
2498
2499         assert( val != NULL );
2500         assert( out != NULL );
2501
2502         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
2503                 val->bv_val, 0, 0 );
2504
2505         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2506
2507         i.bv_val = ber_bvchr( val, '$' );
2508         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2509
2510         sn.bv_val = val->bv_val;
2511         sn.bv_len = i.bv_val - val->bv_val;
2512
2513         i.bv_val++;
2514         i.bv_len = val->bv_len - (sn.bv_len + 1);
2515
2516         /* eat leading zeros */
2517         for( n=0; n < (sn.bv_len-1); n++ ) {
2518                 if( sn.bv_val[n] != '0' ) break;
2519         }
2520         sn.bv_val += n;
2521         sn.bv_len -= n;
2522
2523         for( n=0; n < sn.bv_len; n++ ) {
2524                 if( !ASCII_DIGIT(sn.bv_val[n]) ) {
2525                         return LDAP_INVALID_SYNTAX;
2526                 }
2527         }
2528
2529         /* pretty DN */
2530         rc = dnNormalize( usage, syntax, mr, &i, &newi, ctx );
2531         if( rc ) return LDAP_INVALID_SYNTAX;
2532
2533         /* make room from sn + "$" */
2534         out->bv_len = sn.bv_len + newi.bv_len + 1;
2535         out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2536
2537         if( out->bv_val == NULL ) {
2538                 out->bv_len = 0;
2539                 slap_sl_free( newi.bv_val, ctx );
2540                 return LDAP_OTHER;
2541         }
2542
2543         /* push issuer over */
2544         AC_MEMCPY( &out->bv_val[sn.bv_len+1], out->bv_val, newi.bv_len );
2545         /* insert sn and "$" */
2546         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2547         out->bv_val[sn.bv_len] = '$';
2548         /* terminate */
2549         out->bv_val[out->bv_len] = '\0';
2550
2551         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
2552                 out->bv_val, 0, 0 );
2553
2554         return rc;
2555 }
2556
2557 #ifdef HAVE_TLS
2558 static int
2559 certificateExactNormalize(
2560         slap_mask_t usage,
2561         Syntax *syntax,
2562         MatchingRule *mr,
2563         struct berval *val,
2564         struct berval *normalized,
2565         void *ctx )
2566 {
2567         int rc = LDAP_INVALID_SYNTAX;
2568         unsigned char *p;
2569         char *serial = NULL;
2570         ber_len_t seriallen;
2571         struct berval issuer_dn = BER_BVNULL;
2572         X509_NAME *name = NULL;
2573         ASN1_INTEGER *sn = NULL;
2574         X509 *xcert = NULL;
2575
2576         if( BER_BVISEMPTY( val ) ) goto done;
2577
2578         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
2579                 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
2580         }
2581
2582         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) );
2583
2584         p = (unsigned char *)val->bv_val;
2585         xcert = d2i_X509( NULL, &p, val->bv_len);
2586         if( xcert == NULL ) goto done;
2587
2588         sn=X509_get_serialNumber(xcert);
2589         if ( sn == NULL ) goto done;
2590         serial=i2s_ASN1_INTEGER(0, sn );
2591         if( serial == NULL ) goto done;
2592         seriallen=strlen(serial);
2593
2594         name=X509_get_issuer_name(xcert);
2595         if( name == NULL ) goto done;
2596         rc = dnX509normalize( name, &issuer_dn );
2597         if( rc != LDAP_SUCCESS ) goto done;
2598
2599         normalized->bv_len = seriallen + issuer_dn.bv_len + 1;
2600         normalized->bv_val = ch_malloc(normalized->bv_len+1);
2601         p = (unsigned char *)normalized->bv_val;
2602         AC_MEMCPY(p, serial, seriallen);
2603         p += seriallen;
2604         *p++ = '$';
2605         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
2606         p += issuer_dn.bv_len;
2607         *p = '\0';
2608
2609         Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
2610                 normalized->bv_val, NULL, NULL );
2611
2612 done:
2613         if (xcert) X509_free(xcert);
2614         if (serial) ch_free(serial);
2615         if (issuer_dn.bv_val) ber_memfree(issuer_dn.bv_val);
2616
2617         return rc;
2618 }
2619 #endif /* HAVE_TLS */
2620
2621
2622 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
2623 /* slight optimization - does not need the start parameter */
2624 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
2625 enum { start = 0 };
2626 #endif
2627
2628 static int
2629 check_time_syntax (struct berval *val,
2630         int start,
2631         int *parts,
2632         struct berval *fraction)
2633 {
2634         /*
2635          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
2636          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
2637          * GeneralizedTime supports leap seconds, UTCTime does not.
2638          */
2639         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
2640         static const int mdays[2][12] = {
2641                 /* non-leap years */
2642                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
2643                 /* leap years */
2644                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
2645         };
2646         char *p, *e;
2647         int part, c, c1, c2, tzoffset, leapyear = 0;
2648
2649         p = val->bv_val;
2650         e = p + val->bv_len;
2651
2652 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2653         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
2654 #endif
2655         for (part = start; part < 7 && p < e; part++) {
2656                 c1 = *p;
2657                 if (!ASCII_DIGIT(c1)) {
2658                         break;
2659                 }
2660                 p++;
2661                 if (p == e) {
2662                         return LDAP_INVALID_SYNTAX;
2663                 }
2664                 c = *p++;
2665                 if (!ASCII_DIGIT(c)) {
2666                         return LDAP_INVALID_SYNTAX;
2667                 }
2668                 c += c1 * 10 - '0' * 11;
2669                 if ((part | 1) == 3) {
2670                         --c;
2671                         if (c < 0) {
2672                                 return LDAP_INVALID_SYNTAX;
2673                         }
2674                 }
2675                 if (c >= ceiling[part]) {
2676                         if (! (c == 60 && part == 6 && start == 0))
2677                                 return LDAP_INVALID_SYNTAX;
2678                 }
2679                 parts[part] = c;
2680         }
2681         if (part < 5 + start) {
2682                 return LDAP_INVALID_SYNTAX;
2683         }
2684         for (; part < 9; part++) {
2685                 parts[part] = 0;
2686         }
2687
2688         /* leapyear check for the Gregorian calendar (year>1581) */
2689         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
2690                 leapyear = 1;
2691         }
2692
2693         if (parts[3] >= mdays[leapyear][parts[2]]) {
2694                 return LDAP_INVALID_SYNTAX;
2695         }
2696
2697         if (start == 0) {
2698                 fraction->bv_val = p;
2699                 fraction->bv_len = 0;
2700                 if (p < e && (*p == '.' || *p == ',')) {
2701                         char *end_num;
2702                         while (++p < e && ASCII_DIGIT(*p)) {
2703                                 /* EMTPY */;
2704                         }
2705                         if (p - fraction->bv_val == 1) {
2706                                 return LDAP_INVALID_SYNTAX;
2707                         }
2708                         for (end_num = p; end_num[-1] == '0'; --end_num) {
2709                                 /* EMPTY */;
2710                         }
2711                         c = end_num - fraction->bv_val;
2712                         if (c != 1) fraction->bv_len = c;
2713                 }
2714         }
2715
2716         if (p == e) {
2717                 /* no time zone */
2718                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2719         }
2720
2721         tzoffset = *p++;
2722         switch (tzoffset) {
2723         default:
2724                 return LDAP_INVALID_SYNTAX;
2725         case 'Z':
2726                 /* UTC */
2727                 break;
2728         case '+':
2729         case '-':
2730                 for (part = 7; part < 9 && p < e; part++) {
2731                         c1 = *p;
2732                         if (!ASCII_DIGIT(c1)) {
2733                                 break;
2734                         }
2735                         p++;
2736                         if (p == e) {
2737                                 return LDAP_INVALID_SYNTAX;
2738                         }
2739                         c2 = *p++;
2740                         if (!ASCII_DIGIT(c2)) {
2741                                 return LDAP_INVALID_SYNTAX;
2742                         }
2743                         parts[part] = c1 * 10 + c2 - '0' * 11;
2744                         if (parts[part] >= ceiling[part]) {
2745                                 return LDAP_INVALID_SYNTAX;
2746                         }
2747                 }
2748                 if (part < 8 + start) {
2749                         return LDAP_INVALID_SYNTAX;
2750                 }
2751
2752                 if (tzoffset == '-') {
2753                         /* negative offset to UTC, ie west of Greenwich */
2754                         parts[4] += parts[7];
2755                         parts[5] += parts[8];
2756                         /* offset is just hhmm, no seconds */
2757                         for (part = 6; --part >= 0; ) {
2758                                 if (part != 3) {
2759                                         c = ceiling[part];
2760                                 } else {
2761                                         c = mdays[leapyear][parts[2]];
2762                                 }
2763                                 if (parts[part] >= c) {
2764                                         if (part == 0) {
2765                                                 return LDAP_INVALID_SYNTAX;
2766                                         }
2767                                         parts[part] -= c;
2768                                         parts[part - 1]++;
2769                                         continue;
2770                                 } else if (part != 5) {
2771                                         break;
2772                                 }
2773                         }
2774                 } else {
2775                         /* positive offset to UTC, ie east of Greenwich */
2776                         parts[4] -= parts[7];
2777                         parts[5] -= parts[8];
2778                         for (part = 6; --part >= 0; ) {
2779                                 if (parts[part] < 0) {
2780                                         if (part == 0) {
2781                                                 return LDAP_INVALID_SYNTAX;
2782                                         }
2783                                         if (part != 3) {
2784                                                 c = ceiling[part];
2785                                         } else {
2786                                                 /* make first arg to % non-negative */
2787                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
2788                                         }
2789                                         parts[part] += c;
2790                                         parts[part - 1]--;
2791                                         continue;
2792                                 } else if (part != 5) {
2793                                         break;
2794                                 }
2795                         }
2796                 }
2797         }
2798
2799         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2800 }
2801
2802 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2803
2804 #if 0
2805 static int
2806 xutcTimeNormalize(
2807         Syntax *syntax,
2808         struct berval *val,
2809         struct berval *normalized )
2810 {
2811         int parts[9], rc;
2812
2813         rc = check_time_syntax(val, 1, parts, NULL);
2814         if (rc != LDAP_SUCCESS) {
2815                 return rc;
2816         }
2817
2818         normalized->bv_val = ch_malloc( 14 );
2819         if ( normalized->bv_val == NULL ) {
2820                 return LBER_ERROR_MEMORY;
2821         }
2822
2823         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
2824                 parts[1], parts[2] + 1, parts[3] + 1,
2825                 parts[4], parts[5], parts[6] );
2826         normalized->bv_len = 13;
2827
2828         return LDAP_SUCCESS;
2829 }
2830 #endif /* 0 */
2831
2832 static int
2833 utcTimeValidate(
2834         Syntax *syntax,
2835         struct berval *in )
2836 {
2837         int parts[9];
2838         return check_time_syntax(in, 1, parts, NULL);
2839 }
2840
2841 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
2842
2843 static int
2844 generalizedTimeValidate(
2845         Syntax *syntax,
2846         struct berval *in )
2847 {
2848         int parts[9];
2849         struct berval fraction;
2850         return check_time_syntax(in, 0, parts, &fraction);
2851 }
2852
2853 static int
2854 generalizedTimeNormalize(
2855         slap_mask_t usage,
2856         Syntax *syntax,
2857         MatchingRule *mr,
2858         struct berval *val,
2859         struct berval *normalized,
2860         void *ctx )
2861 {
2862         int parts[9], rc;
2863         unsigned int len;
2864         struct berval fraction;
2865
2866         rc = check_time_syntax(val, 0, parts, &fraction);
2867         if (rc != LDAP_SUCCESS) {
2868                 return rc;
2869         }
2870
2871         len = sizeof("YYYYmmddHHMMSSZ")-1 + fraction.bv_len;
2872         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
2873         if ( BER_BVISNULL( normalized ) ) {
2874                 return LBER_ERROR_MEMORY;
2875         }
2876
2877         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
2878                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
2879                 parts[4], parts[5], parts[6] );
2880         if ( !BER_BVISEMPTY( &fraction ) ) {
2881                 memcpy( normalized->bv_val + sizeof("YYYYmmddHHMMSSZ")-2,
2882                         fraction.bv_val, fraction.bv_len );
2883                 normalized->bv_val[sizeof("YYYYmmddHHMMSSZ")-2] = '.';
2884         }
2885         strcpy( normalized->bv_val + len-1, "Z" );
2886         normalized->bv_len = len;
2887
2888         return LDAP_SUCCESS;
2889 }
2890
2891 static int
2892 generalizedTimeOrderingMatch(
2893         int *matchp,
2894         slap_mask_t flags,
2895         Syntax *syntax,
2896         MatchingRule *mr,
2897         struct berval *value,
2898         void *assertedValue )
2899 {
2900         struct berval *asserted = (struct berval *) assertedValue;
2901         ber_len_t v_len  = value->bv_len;
2902         ber_len_t av_len = asserted->bv_len;
2903
2904         /* ignore trailing 'Z' when comparing */
2905         int match = memcmp( value->bv_val, asserted->bv_val,
2906                 (v_len < av_len ? v_len : av_len) - 1 );
2907         if ( match == 0 ) match = v_len - av_len;
2908
2909         *matchp = match;
2910         return LDAP_SUCCESS;
2911 }
2912
2913 /* Index generation function */
2914 int generalizedTimeIndexer(
2915         slap_mask_t use,
2916         slap_mask_t flags,
2917         Syntax *syntax,
2918         MatchingRule *mr,
2919         struct berval *prefix,
2920         BerVarray values,
2921         BerVarray *keysp,
2922         void *ctx )
2923 {
2924         int i, j;
2925         BerVarray keys;
2926         char tmp[5];
2927         BerValue bvtmp; /* 40 bit index */
2928         struct lutil_tm tm;
2929         struct lutil_timet tt;
2930
2931         bvtmp.bv_len = sizeof(tmp);
2932         bvtmp.bv_val = tmp;
2933         for( i=0; values[i].bv_val != NULL; i++ ) {
2934                 /* just count them */
2935         }
2936
2937         /* we should have at least one value at this point */
2938         assert( i > 0 );
2939
2940         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2941
2942         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
2943         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
2944                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
2945                 /* Use 40 bits of time for key */
2946                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
2947                         lutil_tm2time( &tm, &tt );
2948                         tmp[0] = tt.tt_gsec & 0xff;
2949                         tmp[4] = tt.tt_sec & 0xff;
2950                         tt.tt_sec >>= 8;
2951                         tmp[3] = tt.tt_sec & 0xff;
2952                         tt.tt_sec >>= 8;
2953                         tmp[2] = tt.tt_sec & 0xff;
2954                         tt.tt_sec >>= 8;
2955                         tmp[1] = tt.tt_sec & 0xff;
2956                         
2957                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
2958                 }
2959         }
2960
2961         keys[j].bv_val = NULL;
2962         keys[j].bv_len = 0;
2963
2964         *keysp = keys;
2965
2966         return LDAP_SUCCESS;
2967 }
2968
2969 /* Index generation function */
2970 int generalizedTimeFilter(
2971         slap_mask_t use,
2972         slap_mask_t flags,
2973         Syntax *syntax,
2974         MatchingRule *mr,
2975         struct berval *prefix,
2976         void * assertedValue,
2977         BerVarray *keysp,
2978         void *ctx )
2979 {
2980         BerVarray keys;
2981         char tmp[5];
2982         BerValue bvtmp; /* 40 bit index */
2983         BerValue *value = (BerValue *) assertedValue;
2984         struct lutil_tm tm;
2985         struct lutil_timet tt;
2986         
2987         bvtmp.bv_len = sizeof(tmp);
2988         bvtmp.bv_val = tmp;
2989         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
2990         /* Use 40 bits of time for key */
2991         if ( value->bv_val && value->bv_len >= 10 &&
2992                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
2993
2994                 lutil_tm2time( &tm, &tt );
2995                 tmp[0] = tt.tt_gsec & 0xff;
2996                 tmp[4] = tt.tt_sec & 0xff;
2997                 tt.tt_sec >>= 8;
2998                 tmp[3] = tt.tt_sec & 0xff;
2999                 tt.tt_sec >>= 8;
3000                 tmp[2] = tt.tt_sec & 0xff;
3001                 tt.tt_sec >>= 8;
3002                 tmp[1] = tt.tt_sec & 0xff;
3003
3004                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
3005                 ber_dupbv_x(keys, &bvtmp, ctx );
3006                 keys[1].bv_val = NULL;
3007                 keys[1].bv_len = 0;
3008         } else {
3009                 keys = NULL;
3010         }
3011
3012         *keysp = keys;
3013
3014         return LDAP_SUCCESS;
3015 }
3016
3017 static int
3018 deliveryMethodValidate(
3019         Syntax *syntax,
3020         struct berval *val )
3021 {
3022 #undef LENOF
3023 #define LENOF(s) (sizeof(s)-1)
3024         struct berval tmp = *val;
3025         /*
3026      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
3027          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
3028          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
3029          */
3030 again:
3031         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3032
3033         switch( tmp.bv_val[0] ) {
3034         case 'a':
3035         case 'A':
3036                 if(( tmp.bv_len >= LENOF("any") ) &&
3037                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
3038                 {
3039                         tmp.bv_len -= LENOF("any");
3040                         tmp.bv_val += LENOF("any");
3041                         break;
3042                 }
3043                 return LDAP_INVALID_SYNTAX;
3044
3045         case 'm':
3046         case 'M':
3047                 if(( tmp.bv_len >= LENOF("mhs") ) &&
3048                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
3049                 {
3050                         tmp.bv_len -= LENOF("mhs");
3051                         tmp.bv_val += LENOF("mhs");
3052                         break;
3053                 }
3054                 return LDAP_INVALID_SYNTAX;
3055
3056         case 'p':
3057         case 'P':
3058                 if(( tmp.bv_len >= LENOF("physical") ) &&
3059                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
3060                 {
3061                         tmp.bv_len -= LENOF("physical");
3062                         tmp.bv_val += LENOF("physical");
3063                         break;
3064                 }
3065                 return LDAP_INVALID_SYNTAX;
3066
3067         case 't':
3068         case 'T': /* telex or teletex or telephone */
3069                 if(( tmp.bv_len >= LENOF("telex") ) &&
3070                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
3071                 {
3072                         tmp.bv_len -= LENOF("telex");
3073                         tmp.bv_val += LENOF("telex");
3074                         break;
3075                 }
3076                 if(( tmp.bv_len >= LENOF("teletex") ) &&
3077                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
3078                 {
3079                         tmp.bv_len -= LENOF("teletex");
3080                         tmp.bv_val += LENOF("teletex");
3081                         break;
3082                 }
3083                 if(( tmp.bv_len >= LENOF("telephone") ) &&
3084                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
3085                 {
3086                         tmp.bv_len -= LENOF("telephone");
3087                         tmp.bv_val += LENOF("telephone");
3088                         break;
3089                 }
3090                 return LDAP_INVALID_SYNTAX;
3091
3092         case 'g':
3093         case 'G': /* g3fax or g4fax */
3094                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
3095                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
3096                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
3097                 {
3098                         tmp.bv_len -= LENOF("g3fax");
3099                         tmp.bv_val += LENOF("g3fax");
3100                         break;
3101                 }
3102                 return LDAP_INVALID_SYNTAX;
3103
3104         case 'i':
3105         case 'I':
3106                 if(( tmp.bv_len >= LENOF("ia5") ) &&
3107                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
3108                 {
3109                         tmp.bv_len -= LENOF("ia5");
3110                         tmp.bv_val += LENOF("ia5");
3111                         break;
3112                 }
3113                 return LDAP_INVALID_SYNTAX;
3114
3115         case 'v':
3116         case 'V':
3117                 if(( tmp.bv_len >= LENOF("videotex") ) &&
3118                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
3119                 {
3120                         tmp.bv_len -= LENOF("videotex");
3121                         tmp.bv_val += LENOF("videotex");
3122                         break;
3123                 }
3124                 return LDAP_INVALID_SYNTAX;
3125
3126         default:
3127                 return LDAP_INVALID_SYNTAX;
3128         }
3129
3130         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
3131
3132         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3133                 tmp.bv_len++;
3134                 tmp.bv_val--;
3135         }
3136         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
3137                 tmp.bv_len++;
3138                 tmp.bv_val--;
3139         } else {
3140                 return LDAP_INVALID_SYNTAX;
3141         }
3142         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3143                 tmp.bv_len++;
3144                 tmp.bv_val--;
3145         }
3146
3147         goto again;
3148 }
3149
3150 static int
3151 nisNetgroupTripleValidate(
3152         Syntax *syntax,
3153         struct berval *val )
3154 {
3155         char *p, *e;
3156         int commas = 0;
3157
3158         if ( BER_BVISEMPTY( val ) ) {
3159                 return LDAP_INVALID_SYNTAX;
3160         }
3161
3162         p = (char *)val->bv_val;
3163         e = p + val->bv_len;
3164
3165         if ( *p != '(' /*')'*/ ) {
3166                 return LDAP_INVALID_SYNTAX;
3167         }
3168
3169         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
3170                 if ( *p == ',' ) {
3171                         commas++;
3172                         if ( commas > 2 ) {
3173                                 return LDAP_INVALID_SYNTAX;
3174                         }
3175
3176                 } else if ( !AD_CHAR( *p ) ) {
3177                         return LDAP_INVALID_SYNTAX;
3178                 }
3179         }
3180
3181         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
3182                 return LDAP_INVALID_SYNTAX;
3183         }
3184
3185         p++;
3186
3187         if (p != e) {
3188                 return LDAP_INVALID_SYNTAX;
3189         }
3190
3191         return LDAP_SUCCESS;
3192 }
3193
3194 static int
3195 bootParameterValidate(
3196         Syntax *syntax,
3197         struct berval *val )
3198 {
3199         char *p, *e;
3200
3201         if ( BER_BVISEMPTY( val ) ) {
3202                 return LDAP_INVALID_SYNTAX;
3203         }
3204
3205         p = (char *)val->bv_val;
3206         e = p + val->bv_len;
3207
3208         /* key */
3209         for (; ( p < e ) && ( *p != '=' ); p++ ) {
3210                 if ( !AD_CHAR( *p ) ) {
3211                         return LDAP_INVALID_SYNTAX;
3212                 }
3213         }
3214
3215         if ( *p != '=' ) {
3216                 return LDAP_INVALID_SYNTAX;
3217         }
3218
3219         /* server */
3220         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
3221                 if ( !AD_CHAR( *p ) ) {
3222                         return LDAP_INVALID_SYNTAX;
3223                 }
3224         }
3225
3226         if ( *p != ':' ) {
3227                 return LDAP_INVALID_SYNTAX;
3228         }
3229
3230         /* path */
3231         for ( p++; p < e; p++ ) {
3232                 if ( !SLAP_PRINTABLE( *p ) ) {
3233                         return LDAP_INVALID_SYNTAX;
3234                 }
3235         }
3236
3237         return LDAP_SUCCESS;
3238 }
3239
3240 static int
3241 firstComponentNormalize(
3242         slap_mask_t usage,
3243         Syntax *syntax,
3244         MatchingRule *mr,
3245         struct berval *val,
3246         struct berval *normalized,
3247         void *ctx )
3248 {
3249         int rc;
3250         struct berval comp;
3251         ber_len_t len;
3252
3253         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
3254                 ber_dupbv_x( normalized, val, ctx );
3255                 return LDAP_SUCCESS;
3256         }
3257
3258         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3259
3260         if( val->bv_val[0] != '(' /*')'*/ &&
3261                 val->bv_val[0] != '{' /*'}'*/ )
3262         {
3263                 return LDAP_INVALID_SYNTAX;
3264         }
3265
3266         /* trim leading white space */
3267         for( len=1;
3268                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
3269                 len++ )
3270         {
3271                 /* empty */
3272         }
3273
3274         /* grab next word */
3275         comp.bv_val = &val->bv_val[len];
3276         len = val->bv_len - len;
3277         for( comp.bv_len = 0;
3278                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
3279                 comp.bv_len++ )
3280         {
3281                 /* empty */
3282         }
3283
3284         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
3285                 rc = numericoidValidate( NULL, &comp );
3286         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
3287                 rc = integerValidate( NULL, &comp );
3288         } else {
3289                 rc = LDAP_INVALID_SYNTAX;
3290         }
3291         
3292
3293         if( rc == LDAP_SUCCESS ) {
3294                 ber_dupbv_x( normalized, &comp, ctx );
3295         }
3296
3297         return rc;
3298 }
3299
3300
3301 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
3302 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
3303
3304 static slap_syntax_defs_rec syntax_defs[] = {
3305         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
3306                 X_BINARY X_NOT_H_R ")",
3307                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL},
3308         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
3309                 0, NULL, NULL},
3310         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
3311                 0, NULL, NULL},
3312         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
3313                 X_NOT_H_R ")",
3314                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3315         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
3316                 X_NOT_H_R ")",
3317                 SLAP_SYNTAX_BER, berValidate, NULL},
3318         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
3319                 0, bitStringValidate, NULL },
3320         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
3321                 0, booleanValidate, NULL},
3322         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
3323                 X_BINARY X_NOT_H_R ")",
3324                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, certificateValidate, NULL},
3325         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
3326                 X_BINARY X_NOT_H_R ")",
3327                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3328         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
3329                 X_BINARY X_NOT_H_R ")",
3330                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3331         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
3332                 0, countryStringValidate, NULL},
3333         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
3334                 0, dnValidate, dnPretty},
3335         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
3336                 0, rdnValidate, rdnPretty},
3337 #ifdef LDAP_COMP_MATCH
3338         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
3339                 0, allComponentsValidate, NULL},
3340         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
3341                 0, componentFilterValidate, NULL},
3342 #endif
3343         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
3344                 0, NULL, NULL},
3345         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
3346                 0, deliveryMethodValidate, NULL},
3347         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
3348                 0, UTF8StringValidate, NULL},
3349         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
3350                 0, NULL, NULL},
3351         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
3352                 0, NULL, NULL},
3353         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
3354                 0, NULL, NULL},
3355         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
3356                 0, NULL, NULL},
3357         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
3358                 0, NULL, NULL},
3359         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
3360                 0, printablesStringValidate, NULL},
3361         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
3362                 SLAP_SYNTAX_BLOB, NULL, NULL},
3363         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
3364                 0, generalizedTimeValidate, NULL},
3365         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
3366                 0, NULL, NULL},
3367         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
3368                 0, IA5StringValidate, NULL},
3369         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
3370                 0, integerValidate, NULL},
3371         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
3372                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3373         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
3374                 0, NULL, NULL},
3375         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
3376                 0, NULL, NULL},
3377         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
3378                 0, NULL, NULL},
3379         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
3380                 0, NULL, NULL},
3381         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
3382                 0, NULL, NULL},
3383         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
3384                 0, nameUIDValidate, nameUIDPretty },
3385         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
3386                 0, NULL, NULL},
3387         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
3388                 0, numericStringValidate, NULL},
3389         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
3390                 0, NULL, NULL},
3391         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
3392                 0, numericoidValidate, NULL},
3393         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
3394                 0, IA5StringValidate, NULL},
3395         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
3396                 0, blobValidate, NULL},
3397         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
3398                 0, UTF8StringValidate, NULL},
3399         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
3400                 0, NULL, NULL},
3401         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
3402                 0, NULL, NULL},
3403         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
3404                 0, printableStringValidate, NULL},
3405         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
3406 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
3407                 0, subtreeSpecificationValidate, NULL},
3408         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
3409                 X_BINARY X_NOT_H_R ")",
3410                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
3411         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
3412                 0, printableStringValidate, NULL},
3413         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
3414                 0, NULL, NULL},
3415         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
3416                 0, printablesStringValidate, NULL},
3417 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3418         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
3419                 0, utcTimeValidate, NULL},
3420 #endif
3421         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
3422                 0, NULL, NULL},
3423         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
3424                 0, NULL, NULL},
3425         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
3426                 0, NULL, NULL},
3427         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
3428                 0, NULL, NULL},
3429         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
3430                 0, NULL, NULL},
3431
3432         /* RFC 2307 NIS Syntaxes */
3433         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
3434                 0, nisNetgroupTripleValidate, NULL},
3435         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
3436                 0, bootParameterValidate, NULL},
3437
3438         /* From PKIX *//* This OID is not published yet. */
3439         {"( 1.2.826.0.1.3344810.7.1 DESC 'Certificate Serial Number and Issuer' )",
3440                 SLAP_SYNTAX_HIDE,
3441                 serialNumberAndIssuerValidate,
3442                 serialNumberAndIssuerPretty},
3443
3444 #ifdef SLAPD_AUTHPASSWD
3445         /* needs updating */
3446         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
3447                 SLAP_SYNTAX_HIDE, NULL, NULL},
3448 #endif
3449
3450         {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
3451                 0, UUIDValidate, NULL},
3452
3453         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
3454                 SLAP_SYNTAX_HIDE, csnValidate, NULL},
3455
3456         /* OpenLDAP Void Syntax */
3457         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
3458                 SLAP_SYNTAX_HIDE, inValidate, NULL},
3459
3460 #ifdef SLAP_AUTHZ_SYNTAX
3461         /* FIXME: OID is unused, but not registered yet */
3462         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
3463                 SLAP_SYNTAX_HIDE, authzValidate, authzPretty},
3464 #endif /* SLAP_AUTHZ_SYNTAX */
3465
3466         {NULL, 0, NULL, NULL}
3467 };
3468
3469 char *certificateExactMatchSyntaxes[] = {
3470         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
3471         NULL
3472 };
3473 #ifdef LDAP_COMP_MATCH
3474 char *componentFilterMatchSyntaxes[] = {
3475         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
3476         NULL
3477 };
3478 #endif
3479 char *directoryStringSyntaxes[] = {
3480         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
3481         NULL
3482 };
3483 char *integerFirstComponentMatchSyntaxes[] = {
3484         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
3485         "1.3.6.1.4.1.1466.115.121.1.17" /* ditStructureRuleDescription */,
3486         NULL
3487 };
3488 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
3489         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
3490         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
3491         "1.3.6.1.4.1.1466.115.121.1.16" /* ditContentRuleDescription */,
3492         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
3493         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
3494         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
3495         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
3496         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
3497         NULL
3498 };
3499
3500 /*
3501  * Other matching rules in X.520 that we do not use (yet):
3502  *
3503  * 2.5.13.25    uTCTimeMatch
3504  * 2.5.13.26    uTCTimeOrderingMatch
3505  * 2.5.13.31*   directoryStringFirstComponentMatch
3506  * 2.5.13.32*   wordMatch
3507  * 2.5.13.33*   keywordMatch
3508  * 2.5.13.36    certificatePairExactMatch
3509  * 2.5.13.37    certificatePairMatch
3510  * 2.5.13.38    certificateListExactMatch
3511  * 2.5.13.39    certificateListMatch
3512  * 2.5.13.40    algorithmIdentifierMatch
3513  * 2.5.13.41*   storedPrefixMatch
3514  * 2.5.13.42    attributeCertificateMatch
3515  * 2.5.13.43    readerAndKeyIDMatch
3516  * 2.5.13.44    attributeIntegrityMatch
3517  *
3518  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
3519  */
3520 static slap_mrule_defs_rec mrule_defs[] = {
3521         /*
3522          * EQUALITY matching rules must be listed after associated APPROX
3523          * matching rules.  So, we list all APPROX matching rules first.
3524          */
3525         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
3526                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3527                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3528                 NULL, NULL, directoryStringApproxMatch,
3529                 directoryStringApproxIndexer, directoryStringApproxFilter,
3530                 NULL},
3531
3532         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
3533                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3534                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3535                 NULL, NULL, IA5StringApproxMatch,
3536                 IA5StringApproxIndexer, IA5StringApproxFilter,
3537                 NULL},
3538
3539         /*
3540          * Other matching rules
3541          */
3542         
3543         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
3544                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3545                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3546                 NULL, NULL, octetStringMatch,
3547                 octetStringIndexer, octetStringFilter,
3548                 NULL },
3549
3550         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
3551                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3552                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3553                 NULL, dnNormalize, dnMatch,
3554                 octetStringIndexer, octetStringFilter,
3555                 NULL },
3556
3557         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
3558                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3559                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3560                 NULL, dnNormalize, dnRelativeMatch,
3561                 NULL, NULL,
3562                 NULL },
3563
3564         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
3565                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3566                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3567                 NULL, dnNormalize, dnRelativeMatch,
3568                 NULL, NULL,
3569                 NULL },
3570
3571         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
3572                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3573                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3574                 NULL, dnNormalize, dnRelativeMatch,
3575                 NULL, NULL,
3576                 NULL },
3577
3578         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
3579                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3580                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3581                 NULL, dnNormalize, dnRelativeMatch,
3582                 NULL, NULL,
3583                 NULL },
3584
3585         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
3586                 "SYNTAX 1.2.36.79672281.1.5.0 )",
3587                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3588                 NULL, rdnNormalize, rdnMatch,
3589                 octetStringIndexer, octetStringFilter,
3590                 NULL },
3591
3592 #ifdef LDAP_COMP_MATCH
3593         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
3594                 "SYNTAX 1.2.36.79672281.1.5.2 )",
3595                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
3596                 NULL, NULL , componentFilterMatch,
3597                 octetStringIndexer, octetStringFilter,
3598                 NULL },
3599
3600         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
3601                 "SYNTAX 1.2.36.79672281.1.5.3 )",
3602                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
3603                 NULL, NULL , allComponentsMatch,
3604                 octetStringIndexer, octetStringFilter,
3605                 NULL },
3606
3607         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
3608                 "SYNTAX 1.2.36.79672281.1.5.3 )",
3609                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
3610                 NULL, NULL , directoryComponentsMatch,
3611                 octetStringIndexer, octetStringFilter,
3612                 NULL },
3613 #endif
3614
3615         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
3616                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3617                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3618                 NULL, UTF8StringNormalize, octetStringMatch,
3619                 octetStringIndexer, octetStringFilter,
3620                 directoryStringApproxMatchOID },
3621
3622         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
3623                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3624                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3625                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3626                 NULL, NULL,
3627                 "caseIgnoreMatch" },
3628
3629         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
3630                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3631                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3632                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
3633                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3634                 "caseIgnoreMatch" },
3635
3636         {"( 2.5.13.5 NAME 'caseExactMatch' "
3637                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3638                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3639                 NULL, UTF8StringNormalize, octetStringMatch,
3640                 octetStringIndexer, octetStringFilter,
3641                 directoryStringApproxMatchOID },
3642
3643         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
3644                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3645                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3646                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3647                 NULL, NULL,
3648                 "caseExactMatch" },
3649
3650         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
3651                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3652                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3653                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
3654                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3655                 "caseExactMatch" },
3656
3657         {"( 2.5.13.8 NAME 'numericStringMatch' "
3658                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3659                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3660                 NULL, numericStringNormalize, octetStringMatch,
3661                 octetStringIndexer, octetStringFilter,
3662                 NULL },
3663
3664         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
3665                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3666                 SLAP_MR_ORDERING, NULL,
3667                 NULL, numericStringNormalize, octetStringOrderingMatch,
3668                 NULL, NULL,
3669                 "numericStringMatch" },
3670
3671         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
3672                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3673                 SLAP_MR_SUBSTR, NULL,
3674                 NULL, numericStringNormalize, octetStringSubstringsMatch,
3675                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3676                 "numericStringMatch" },
3677
3678         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
3679                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
3680                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3681                 NULL, NULL, NULL, NULL, NULL, NULL },
3682
3683         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
3684                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3685                 SLAP_MR_SUBSTR, NULL,
3686                 NULL, NULL, NULL, NULL, NULL,
3687                 "caseIgnoreListMatch" },
3688
3689         {"( 2.5.13.13 NAME 'booleanMatch' "
3690                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
3691                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3692                 NULL, NULL, booleanMatch,
3693                 octetStringIndexer, octetStringFilter,
3694                 NULL },
3695
3696         {"( 2.5.13.14 NAME 'integerMatch' "
3697                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3698                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3699                 NULL, NULL, integerMatch,
3700                 octetStringIndexer, octetStringFilter,
3701                 NULL },
3702
3703         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
3704                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3705                 SLAP_MR_ORDERING, NULL,
3706                 NULL, NULL, integerMatch,
3707                 NULL, NULL,
3708                 "integerMatch" },
3709
3710         {"( 2.5.13.16 NAME 'bitStringMatch' "
3711                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
3712                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3713                 NULL, NULL, octetStringMatch,
3714                 octetStringIndexer, octetStringFilter,
3715                 NULL },
3716
3717         {"( 2.5.13.17 NAME 'octetStringMatch' "
3718                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3719                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3720                 NULL, NULL, octetStringMatch,
3721                 octetStringIndexer, octetStringFilter,
3722                 NULL },
3723
3724         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
3725                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3726                 SLAP_MR_ORDERING, NULL,
3727                 NULL, NULL, octetStringOrderingMatch,
3728                 NULL, NULL,
3729                 "octetStringMatch" },
3730
3731         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
3732                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3733                 SLAP_MR_SUBSTR, NULL,
3734                 NULL, NULL, octetStringSubstringsMatch,
3735                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3736                 "octetStringMatch" },
3737
3738         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
3739                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
3740                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3741                 NULL,
3742                 telephoneNumberNormalize, octetStringMatch,
3743                 octetStringIndexer, octetStringFilter,
3744                 NULL },
3745
3746         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
3747                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3748                 SLAP_MR_SUBSTR, NULL,
3749                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
3750                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3751                 "telephoneNumberMatch" },
3752
3753         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
3754                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
3755                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3756                 NULL, NULL, NULL, NULL, NULL, NULL },
3757
3758         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
3759                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
3760                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3761                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
3762                 uniqueMemberIndexer, uniqueMemberFilter,
3763                 NULL },
3764
3765         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
3766                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
3767                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3768                 NULL, NULL, NULL, NULL, NULL, NULL },
3769
3770         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
3771                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3772                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
3773                 NULL, generalizedTimeNormalize, octetStringMatch,
3774                 generalizedTimeIndexer, generalizedTimeFilter,
3775                 NULL },
3776
3777         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
3778                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3779                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
3780                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
3781                 NULL, NULL,
3782                 "generalizedTimeMatch" },
3783
3784         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
3785                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3786                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3787                         integerFirstComponentMatchSyntaxes,
3788                 NULL, firstComponentNormalize, integerMatch,
3789                 octetStringIndexer, octetStringFilter,
3790                 NULL },
3791
3792         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
3793                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3794                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3795                         objectIdentifierFirstComponentMatchSyntaxes,
3796                 NULL, firstComponentNormalize, octetStringMatch,
3797                 octetStringIndexer, octetStringFilter,
3798                 NULL },
3799
3800         {"( 2.5.13.34 NAME 'certificateExactMatch' "
3801                 "SYNTAX 1.2.826.0.1.3344810.7.1 )",
3802                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
3803 #ifdef HAVE_TLS
3804                 NULL, certificateExactNormalize, octetStringMatch,
3805                 octetStringIndexer, octetStringFilter,
3806 #else
3807                 NULL, NULL, NULL, NULL, NULL,
3808 #endif
3809                 NULL },
3810
3811         {"( 2.5.13.35 NAME 'certificateMatch' "
3812                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )",
3813                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3814 #ifdef HAVE_TLS
3815                 NULL, NULL, octetStringMatch,
3816                 octetStringIndexer, octetStringFilter,
3817 #else
3818                 NULL, NULL, NULL, NULL, NULL,
3819 #endif
3820                 NULL },
3821
3822         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
3823                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3824                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3825                 NULL, IA5StringNormalize, octetStringMatch,
3826                 octetStringIndexer, octetStringFilter,
3827                 IA5StringApproxMatchOID },
3828
3829         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
3830                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3831                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3832                 NULL, IA5StringNormalize, octetStringMatch,
3833                 octetStringIndexer, octetStringFilter,
3834                 IA5StringApproxMatchOID },
3835
3836         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
3837                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3838                 SLAP_MR_SUBSTR, NULL,
3839                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
3840                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3841                 "caseIgnoreIA5Match" },
3842
3843         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
3844                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3845                 SLAP_MR_SUBSTR, NULL,
3846                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
3847                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3848                 "caseExactIA5Match" },
3849
3850 #ifdef SLAPD_AUTHPASSWD
3851         /* needs updating */
3852         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
3853                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3854                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3855                 NULL, NULL, authPasswordMatch,
3856                 NULL, NULL,
3857                 NULL},
3858 #endif
3859
3860         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
3861                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3862                 SLAP_MR_EXT, NULL,
3863                 NULL, NULL, integerBitAndMatch,
3864                 NULL, NULL,
3865                 "integerMatch" },
3866
3867         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
3868                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3869                 SLAP_MR_EXT, NULL,
3870                 NULL, NULL, integerBitOrMatch,
3871                 NULL, NULL,
3872                 "integerMatch" },
3873
3874         {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
3875                 "SYNTAX 1.3.6.1.1.16.1 )",
3876                 SLAP_MR_EQUALITY, NULL,
3877                 NULL, UUIDNormalize, octetStringMatch,
3878                 octetStringIndexer, octetStringFilter,
3879                 NULL},
3880
3881         {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
3882                 "SYNTAX 1.3.6.1.1.16.1 )",
3883                 SLAP_MR_ORDERING, NULL,
3884                 NULL, UUIDNormalize, octetStringOrderingMatch,
3885                 octetStringIndexer, octetStringFilter,
3886                 "UUIDMatch"},
3887
3888         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
3889                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
3890                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
3891                 NULL, NULL, csnMatch,
3892                 csnIndexer, csnFilter,
3893                 NULL},
3894
3895         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
3896                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
3897                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
3898                 NULL, NULL, csnOrderingMatch,
3899                 NULL, NULL,
3900                 "CSNMatch" },
3901
3902 #ifdef SLAP_AUTHZ_SYNTAX
3903         /* FIXME: OID is unused, but not registered yet */
3904         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
3905                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
3906                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3907                 NULL, authzNormalize, authzMatch,
3908                 NULL, NULL,
3909                 NULL},
3910 #endif /* SLAP_AUTHZ_SYNTAX */
3911
3912         {NULL, SLAP_MR_NONE, NULL,
3913                 NULL, NULL, NULL, NULL, NULL,
3914                 NULL }
3915 };
3916
3917 int
3918 slap_schema_init( void )
3919 {
3920         int             res;
3921         int             i;
3922
3923         /* we should only be called once (from main) */
3924         assert( schema_init_done == 0 );
3925
3926         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
3927                 res = register_syntax( &syntax_defs[i] );
3928
3929                 if ( res ) {
3930                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
3931                                  syntax_defs[i].sd_desc );
3932                         return LDAP_OTHER;
3933                 }
3934         }
3935
3936         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
3937                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
3938                         mrule_defs[i].mrd_compat_syntaxes == NULL )
3939                 {
3940                         fprintf( stderr,
3941                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
3942                                  mrule_defs[i].mrd_desc );
3943                         continue;
3944                 }
3945
3946                 res = register_matching_rule( &mrule_defs[i] );
3947
3948                 if ( res ) {
3949                         fprintf( stderr,
3950                                 "slap_schema_init: Error registering matching rule %s\n",
3951                                  mrule_defs[i].mrd_desc );
3952                         return LDAP_OTHER;
3953                 }
3954         }
3955
3956         res = slap_schema_load();
3957         schema_init_done = 1;
3958         return res;
3959 }
3960
3961 void
3962 schema_destroy( void )
3963 {
3964         oidm_destroy();
3965         oc_destroy();
3966         at_destroy();
3967         mr_destroy();
3968         mru_destroy();
3969         syn_destroy();
3970
3971         ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
3972         ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
3973 }