]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
ITS#5401
[openldap] / servers / slapd / schema_init.c
1 /* schema_init.c - init builtin schema */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2008 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20 #ifdef HAVE_LIMITS_H
21 #include <limits.h>
22 #endif
23
24 #include <ac/ctype.h>
25 #include <ac/errno.h>
26 #include <ac/string.h>
27 #include <ac/socket.h>
28
29 #include "slap.h"
30
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         for(i=0; i < val->bv_len; i++) {
2084                 if( !LDAP_ASCII(val->bv_val[i]) ) {
2085                         return LDAP_INVALID_SYNTAX;
2086                 }
2087         }
2088
2089         return LDAP_SUCCESS;
2090 }
2091
2092 static int
2093 IA5StringNormalize(
2094         slap_mask_t use,
2095         Syntax *syntax,
2096         MatchingRule *mr,
2097         struct berval *val,
2098         struct berval *normalized,
2099         void *ctx )
2100 {
2101         char *p, *q;
2102         int casefold = !SLAP_MR_ASSOCIATED(mr, slap_schema.si_mr_caseExactIA5Match);
2103
2104         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
2105
2106         p = val->bv_val;
2107
2108         /* Ignore initial whitespace */
2109         while ( ASCII_SPACE( *p ) ) p++;
2110
2111         normalized->bv_val = ber_strdup_x( p, ctx );
2112         p = q = normalized->bv_val;
2113
2114         while ( *p ) {
2115                 if ( ASCII_SPACE( *p ) ) {
2116                         *q++ = *p++;
2117
2118                         /* Ignore the extra whitespace */
2119                         while ( ASCII_SPACE( *p ) ) {
2120                                 p++;
2121                         }
2122
2123                 } else if ( casefold ) {
2124                         /* Most IA5 rules require casefolding */
2125                         *q++ = TOLOWER(*p); p++;
2126
2127                 } else {
2128                         *q++ = *p++;
2129                 }
2130         }
2131
2132         assert( normalized->bv_val <= p );
2133         assert( q <= p );
2134
2135         /*
2136          * If the string ended in space, backup the pointer one
2137          * position.  One is enough because the above loop collapsed
2138          * all whitespace to a single space.
2139          */
2140         if ( ASCII_SPACE( q[-1] ) ) --q;
2141
2142         /* null terminate */
2143         *q = '\0';
2144
2145         normalized->bv_len = q - normalized->bv_val;
2146
2147         return LDAP_SUCCESS;
2148 }
2149
2150 static int
2151 UUIDValidate(
2152         Syntax *syntax,
2153         struct berval *in )
2154 {
2155         int i;
2156         if( in->bv_len != 36 ) {
2157                 return LDAP_INVALID_SYNTAX;
2158         }
2159
2160         for( i=0; i<36; i++ ) {
2161                 switch(i) {
2162                         case 8:
2163                         case 13:
2164                         case 18:
2165                         case 23:
2166                                 if( in->bv_val[i] != '-' ) {
2167                                         return LDAP_INVALID_SYNTAX;
2168                                 }
2169                                 break;
2170                         default:
2171                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2172                                         return LDAP_INVALID_SYNTAX;
2173                                 }
2174                 }
2175         }
2176         
2177         return LDAP_SUCCESS;
2178 }
2179
2180 static int
2181 UUIDPretty(
2182         Syntax *syntax,
2183         struct berval *in,
2184         struct berval *out,
2185         void *ctx )
2186 {
2187         int i;
2188         int rc=LDAP_INVALID_SYNTAX;
2189
2190         assert( in != NULL );
2191         assert( out != NULL );
2192
2193         if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2194
2195         out->bv_len = 36;
2196         out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2197
2198         for( i=0; i<36; i++ ) {
2199                 switch(i) {
2200                         case 8:
2201                         case 13:
2202                         case 18:
2203                         case 23:
2204                                 if( in->bv_val[i] != '-' ) {
2205                                         goto handle_error;
2206                                 }
2207                                 out->bv_val[i] = '-';
2208                                 break;
2209
2210                         default:
2211                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2212                                         goto handle_error;
2213                                 }
2214                                 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2215                 }
2216         }
2217
2218         rc = LDAP_SUCCESS;
2219         out->bv_val[ out->bv_len ] = '\0';
2220
2221         if( 0 ) {
2222 handle_error:
2223                 slap_sl_free( out->bv_val, ctx );
2224                 out->bv_val = NULL;
2225         }
2226
2227         return rc;
2228 }
2229
2230 int
2231 UUIDNormalize(
2232         slap_mask_t usage,
2233         Syntax *syntax,
2234         MatchingRule *mr,
2235         struct berval *val,
2236         struct berval *normalized,
2237         void *ctx )
2238 {
2239         unsigned char octet = '\0';
2240         int i;
2241         int j;
2242         normalized->bv_len = 16;
2243         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2244
2245         for( i=0, j=0; i<36; i++ ) {
2246                 unsigned char nibble;
2247                 if( val->bv_val[i] == '-' ) {
2248                         continue;
2249
2250                 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2251                         nibble = val->bv_val[i] - '0';
2252
2253                 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2254                         nibble = val->bv_val[i] - ('a'-10);
2255
2256                 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2257                         nibble = val->bv_val[i] - ('A'-10);
2258
2259                 } else {
2260                         slap_sl_free( normalized->bv_val, ctx );
2261                         return LDAP_INVALID_SYNTAX;
2262                 }
2263
2264                 if( j & 1 ) {
2265                         octet |= nibble;
2266                         normalized->bv_val[j>>1] = octet;
2267                 } else {
2268                         octet = nibble << 4;
2269                 }
2270                 j++;
2271         }
2272
2273         normalized->bv_val[normalized->bv_len] = 0;
2274         return LDAP_SUCCESS;
2275 }
2276
2277
2278
2279 static int
2280 numericStringValidate(
2281         Syntax *syntax,
2282         struct berval *in )
2283 {
2284         ber_len_t i;
2285
2286         if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2287
2288         for(i=0; i < in->bv_len; i++) {
2289                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2290                         return LDAP_INVALID_SYNTAX;
2291                 }
2292         }
2293
2294         return LDAP_SUCCESS;
2295 }
2296
2297 static int
2298 numericStringNormalize(
2299         slap_mask_t usage,
2300         Syntax *syntax,
2301         MatchingRule *mr,
2302         struct berval *val,
2303         struct berval *normalized,
2304         void *ctx )
2305 {
2306         /* removal all spaces */
2307         char *p, *q;
2308
2309         assert( !BER_BVISEMPTY( val ) );
2310
2311         normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2312
2313         p = val->bv_val;
2314         q = normalized->bv_val;
2315
2316         while ( *p ) {
2317                 if ( ASCII_SPACE( *p ) ) {
2318                         /* Ignore whitespace */
2319                         p++;
2320                 } else {
2321                         *q++ = *p++;
2322                 }
2323         }
2324
2325         /* we should have copied no more then is in val */
2326         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2327
2328         /* null terminate */
2329         *q = '\0';
2330
2331         normalized->bv_len = q - normalized->bv_val;
2332
2333         if( BER_BVISEMPTY( normalized ) ) {
2334                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2335                 normalized->bv_val[0] = ' ';
2336                 normalized->bv_val[1] = '\0';
2337                 normalized->bv_len = 1;
2338         }
2339
2340         return LDAP_SUCCESS;
2341 }
2342
2343 /*
2344  * Integer conversion macros that will use the largest available
2345  * type.
2346  */
2347 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
2348 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
2349 # define SLAP_LONG           long long
2350 #else
2351 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
2352 # define SLAP_LONG           long
2353 #endif /* HAVE_STRTOLL ... */
2354
2355 static int
2356 integerBitAndMatch(
2357         int *matchp,
2358         slap_mask_t flags,
2359         Syntax *syntax,
2360         MatchingRule *mr,
2361         struct berval *value,
2362         void *assertedValue )
2363 {
2364         SLAP_LONG lValue, lAssertedValue;
2365
2366         errno = 0;
2367         /* safe to assume integers are NUL terminated? */
2368         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2369         if( errno == ERANGE )
2370         {
2371                 return LDAP_CONSTRAINT_VIOLATION;
2372         }
2373
2374         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2375                 NULL, 10);
2376         if( errno == ERANGE )
2377         {
2378                 return LDAP_CONSTRAINT_VIOLATION;
2379         }
2380
2381         *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2382         return LDAP_SUCCESS;
2383 }
2384
2385 static int
2386 integerBitOrMatch(
2387         int *matchp,
2388         slap_mask_t flags,
2389         Syntax *syntax,
2390         MatchingRule *mr,
2391         struct berval *value,
2392         void *assertedValue )
2393 {
2394         SLAP_LONG lValue, lAssertedValue;
2395
2396         errno = 0;
2397         /* safe to assume integers are NUL terminated? */
2398         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2399         if( errno == ERANGE )
2400         {
2401                 return LDAP_CONSTRAINT_VIOLATION;
2402         }
2403
2404         lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2405                 NULL, 10);
2406         if( errno == ERANGE )
2407         {
2408                 return LDAP_CONSTRAINT_VIOLATION;
2409         }
2410
2411         *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2412         return LDAP_SUCCESS;
2413 }
2414
2415 static int
2416 serialNumberAndIssuerValidate(
2417         Syntax *syntax,
2418         struct berval *in )
2419 {
2420         int rc;
2421         ber_len_t n;
2422         struct berval sn, i;
2423         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2424
2425         i.bv_val = ber_bvchr( in, '$' );
2426         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2427
2428         sn.bv_val = in->bv_val;
2429         sn.bv_len = i.bv_val - in->bv_val;
2430
2431         i.bv_val++;
2432         i.bv_len = in->bv_len - (sn.bv_len + 1);
2433
2434         /* validate serial number (strict for now) */
2435         for( n=0; n < sn.bv_len; n++ ) {
2436                 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2437         }
2438
2439         /* validate DN */
2440         rc = dnValidate( NULL, &i );
2441         if( rc ) return LDAP_INVALID_SYNTAX;
2442
2443         return LDAP_SUCCESS;
2444 }
2445
2446 int
2447 serialNumberAndIssuerPretty(
2448         Syntax *syntax,
2449         struct berval *val,
2450         struct berval *out,
2451         void *ctx )
2452 {
2453         int rc;
2454         ber_len_t n;
2455         struct berval sn, i, newi;
2456
2457         assert( val != NULL );
2458         assert( out != NULL );
2459
2460         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
2461                 val->bv_val, 0, 0 );
2462
2463         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2464
2465         i.bv_val = ber_bvchr( val, '$' );
2466         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2467
2468         sn.bv_val = val->bv_val;
2469         sn.bv_len = i.bv_val - val->bv_val;
2470
2471         i.bv_val++;
2472         i.bv_len = val->bv_len - (sn.bv_len + 1);
2473
2474         /* eat leading zeros */
2475         for( n=0; n < (sn.bv_len-1); n++ ) {
2476                 if( sn.bv_val[n] != '0' ) break;
2477         }
2478         sn.bv_val += n;
2479         sn.bv_len -= n;
2480
2481         for( n=0; n < sn.bv_len; n++ ) {
2482                 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2483         }
2484
2485         /* pretty DN */
2486         rc = dnPretty( syntax, &i, &newi, ctx );
2487         if( rc ) return LDAP_INVALID_SYNTAX;
2488
2489         /* make room from sn + "$" */
2490         out->bv_len = sn.bv_len + newi.bv_len + 1;
2491         out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2492
2493         if( out->bv_val == NULL ) {
2494                 out->bv_len = 0;
2495                 slap_sl_free( newi.bv_val, ctx );
2496                 return LDAP_OTHER;
2497         }
2498
2499         /* push issuer over */
2500         AC_MEMCPY( &out->bv_val[sn.bv_len+1], out->bv_val, newi.bv_len );
2501         /* insert sn and "$" */
2502         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2503         out->bv_val[sn.bv_len] = '$';
2504         /* terminate */
2505         out->bv_val[out->bv_len] = '\0';
2506
2507         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
2508                 out->bv_val, 0, 0 );
2509
2510         return LDAP_SUCCESS;
2511 }
2512
2513 /*
2514  * This routine is called by certificateExactNormalize when
2515  * certificateExactNormalize receives a search string instead of
2516  * a certificate. This routine checks if the search value is valid
2517  * and then returns the normalized value
2518  */
2519 static int
2520 serialNumberAndIssuerNormalize(
2521         slap_mask_t usage,
2522         Syntax *syntax,
2523         MatchingRule *mr,
2524         struct berval *val,
2525         struct berval *out,
2526         void *ctx )
2527 {
2528         int rc;
2529         ber_len_t n;
2530         struct berval sn, i, newi;
2531
2532         assert( val != NULL );
2533         assert( out != NULL );
2534
2535         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
2536                 val->bv_val, 0, 0 );
2537
2538         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2539
2540         i.bv_val = ber_bvchr( val, '$' );
2541         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2542
2543         sn.bv_val = val->bv_val;
2544         sn.bv_len = i.bv_val - val->bv_val;
2545
2546         i.bv_val++;
2547         i.bv_len = val->bv_len - (sn.bv_len + 1);
2548
2549         /* eat leading zeros */
2550         for( n=0; n < (sn.bv_len-1); n++ ) {
2551                 if( sn.bv_val[n] != '0' ) break;
2552         }
2553         sn.bv_val += n;
2554         sn.bv_len -= n;
2555
2556         for( n=0; n < sn.bv_len; n++ ) {
2557                 if( !ASCII_DIGIT(sn.bv_val[n]) ) {
2558                         return LDAP_INVALID_SYNTAX;
2559                 }
2560         }
2561
2562         /* pretty DN */
2563         rc = dnNormalize( usage, syntax, mr, &i, &newi, ctx );
2564         if( rc ) return LDAP_INVALID_SYNTAX;
2565
2566         /* make room from sn + "$" */
2567         out->bv_len = sn.bv_len + newi.bv_len + 1;
2568         out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2569
2570         if( out->bv_val == NULL ) {
2571                 out->bv_len = 0;
2572                 slap_sl_free( newi.bv_val, ctx );
2573                 return LDAP_OTHER;
2574         }
2575
2576         /* push issuer over */
2577         AC_MEMCPY( &out->bv_val[sn.bv_len+1], out->bv_val, newi.bv_len );
2578         /* insert sn and "$" */
2579         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2580         out->bv_val[sn.bv_len] = '$';
2581         /* terminate */
2582         out->bv_val[out->bv_len] = '\0';
2583
2584         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
2585                 out->bv_val, 0, 0 );
2586
2587         return rc;
2588 }
2589
2590 #ifdef HAVE_TLS
2591 static int
2592 certificateExactNormalize(
2593         slap_mask_t usage,
2594         Syntax *syntax,
2595         MatchingRule *mr,
2596         struct berval *val,
2597         struct berval *normalized,
2598         void *ctx )
2599 {
2600         int rc = LDAP_INVALID_SYNTAX;
2601         unsigned char *p;
2602         char *serial = NULL;
2603         ber_len_t seriallen;
2604         struct berval issuer_dn = BER_BVNULL;
2605         X509_NAME *name = NULL;
2606         ASN1_INTEGER *sn = NULL;
2607         X509 *xcert = NULL;
2608
2609         if( BER_BVISEMPTY( val ) ) goto done;
2610
2611         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
2612                 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
2613         }
2614
2615         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) );
2616
2617         p = (unsigned char *)val->bv_val;
2618         xcert = d2i_X509( NULL, &p, val->bv_len);
2619         if( xcert == NULL ) goto done;
2620
2621         sn=X509_get_serialNumber(xcert);
2622         if ( sn == NULL ) goto done;
2623         serial=i2s_ASN1_INTEGER(0, sn );
2624         if( serial == NULL ) goto done;
2625         seriallen=strlen(serial);
2626
2627         name=X509_get_issuer_name(xcert);
2628         if( name == NULL ) goto done;
2629         rc = dnX509normalize( name, &issuer_dn );
2630         if( rc != LDAP_SUCCESS ) goto done;
2631
2632         normalized->bv_len = seriallen + issuer_dn.bv_len + 1;
2633         normalized->bv_val = ch_malloc(normalized->bv_len+1);
2634         p = (unsigned char *)normalized->bv_val;
2635         AC_MEMCPY(p, serial, seriallen);
2636         p += seriallen;
2637         *p++ = '$';
2638         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
2639         p += issuer_dn.bv_len;
2640         *p = '\0';
2641
2642         Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
2643                 normalized->bv_val, NULL, NULL );
2644
2645 done:
2646         if (xcert) X509_free(xcert);
2647         if (serial) ch_free(serial);
2648         if (issuer_dn.bv_val) ber_memfree(issuer_dn.bv_val);
2649
2650         return rc;
2651 }
2652 #endif /* HAVE_TLS */
2653
2654
2655 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
2656 /* slight optimization - does not need the start parameter */
2657 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
2658 enum { start = 0 };
2659 #endif
2660
2661 static int
2662 check_time_syntax (struct berval *val,
2663         int start,
2664         int *parts,
2665         struct berval *fraction)
2666 {
2667         /*
2668          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
2669          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
2670          * GeneralizedTime supports leap seconds, UTCTime does not.
2671          */
2672         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
2673         static const int mdays[2][12] = {
2674                 /* non-leap years */
2675                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
2676                 /* leap years */
2677                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
2678         };
2679         char *p, *e;
2680         int part, c, c1, c2, tzoffset, leapyear = 0;
2681
2682         p = val->bv_val;
2683         e = p + val->bv_len;
2684
2685 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2686         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
2687 #endif
2688         for (part = start; part < 7 && p < e; part++) {
2689                 c1 = *p;
2690                 if (!ASCII_DIGIT(c1)) {
2691                         break;
2692                 }
2693                 p++;
2694                 if (p == e) {
2695                         return LDAP_INVALID_SYNTAX;
2696                 }
2697                 c = *p++;
2698                 if (!ASCII_DIGIT(c)) {
2699                         return LDAP_INVALID_SYNTAX;
2700                 }
2701                 c += c1 * 10 - '0' * 11;
2702                 if ((part | 1) == 3) {
2703                         --c;
2704                         if (c < 0) {
2705                                 return LDAP_INVALID_SYNTAX;
2706                         }
2707                 }
2708                 if (c >= ceiling[part]) {
2709                         if (! (c == 60 && part == 6 && start == 0))
2710                                 return LDAP_INVALID_SYNTAX;
2711                 }
2712                 parts[part] = c;
2713         }
2714         if (part < 5 + start) {
2715                 return LDAP_INVALID_SYNTAX;
2716         }
2717         for (; part < 9; part++) {
2718                 parts[part] = 0;
2719         }
2720
2721         /* leapyear check for the Gregorian calendar (year>1581) */
2722         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
2723                 leapyear = 1;
2724         }
2725
2726         if (parts[3] >= mdays[leapyear][parts[2]]) {
2727                 return LDAP_INVALID_SYNTAX;
2728         }
2729
2730         if (start == 0) {
2731                 fraction->bv_val = p;
2732                 fraction->bv_len = 0;
2733                 if (p < e && (*p == '.' || *p == ',')) {
2734                         char *end_num;
2735                         while (++p < e && ASCII_DIGIT(*p)) {
2736                                 /* EMTPY */;
2737                         }
2738                         if (p - fraction->bv_val == 1) {
2739                                 return LDAP_INVALID_SYNTAX;
2740                         }
2741                         for (end_num = p; end_num[-1] == '0'; --end_num) {
2742                                 /* EMPTY */;
2743                         }
2744                         c = end_num - fraction->bv_val;
2745                         if (c != 1) fraction->bv_len = c;
2746                 }
2747         }
2748
2749         if (p == e) {
2750                 /* no time zone */
2751                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2752         }
2753
2754         tzoffset = *p++;
2755         switch (tzoffset) {
2756         default:
2757                 return LDAP_INVALID_SYNTAX;
2758         case 'Z':
2759                 /* UTC */
2760                 break;
2761         case '+':
2762         case '-':
2763                 for (part = 7; part < 9 && p < e; part++) {
2764                         c1 = *p;
2765                         if (!ASCII_DIGIT(c1)) {
2766                                 break;
2767                         }
2768                         p++;
2769                         if (p == e) {
2770                                 return LDAP_INVALID_SYNTAX;
2771                         }
2772                         c2 = *p++;
2773                         if (!ASCII_DIGIT(c2)) {
2774                                 return LDAP_INVALID_SYNTAX;
2775                         }
2776                         parts[part] = c1 * 10 + c2 - '0' * 11;
2777                         if (parts[part] >= ceiling[part]) {
2778                                 return LDAP_INVALID_SYNTAX;
2779                         }
2780                 }
2781                 if (part < 8 + start) {
2782                         return LDAP_INVALID_SYNTAX;
2783                 }
2784
2785                 if (tzoffset == '-') {
2786                         /* negative offset to UTC, ie west of Greenwich */
2787                         parts[4] += parts[7];
2788                         parts[5] += parts[8];
2789                         /* offset is just hhmm, no seconds */
2790                         for (part = 6; --part >= 0; ) {
2791                                 if (part != 3) {
2792                                         c = ceiling[part];
2793                                 } else {
2794                                         c = mdays[leapyear][parts[2]];
2795                                 }
2796                                 if (parts[part] >= c) {
2797                                         if (part == 0) {
2798                                                 return LDAP_INVALID_SYNTAX;
2799                                         }
2800                                         parts[part] -= c;
2801                                         parts[part - 1]++;
2802                                         continue;
2803                                 } else if (part != 5) {
2804                                         break;
2805                                 }
2806                         }
2807                 } else {
2808                         /* positive offset to UTC, ie east of Greenwich */
2809                         parts[4] -= parts[7];
2810                         parts[5] -= parts[8];
2811                         for (part = 6; --part >= 0; ) {
2812                                 if (parts[part] < 0) {
2813                                         if (part == 0) {
2814                                                 return LDAP_INVALID_SYNTAX;
2815                                         }
2816                                         if (part != 3) {
2817                                                 c = ceiling[part];
2818                                         } else {
2819                                                 /* make first arg to % non-negative */
2820                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
2821                                         }
2822                                         parts[part] += c;
2823                                         parts[part - 1]--;
2824                                         continue;
2825                                 } else if (part != 5) {
2826                                         break;
2827                                 }
2828                         }
2829                 }
2830         }
2831
2832         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2833 }
2834
2835 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2836
2837 #if 0
2838 static int
2839 xutcTimeNormalize(
2840         Syntax *syntax,
2841         struct berval *val,
2842         struct berval *normalized )
2843 {
2844         int parts[9], rc;
2845
2846         rc = check_time_syntax(val, 1, parts, NULL);
2847         if (rc != LDAP_SUCCESS) {
2848                 return rc;
2849         }
2850
2851         normalized->bv_val = ch_malloc( 14 );
2852         if ( normalized->bv_val == NULL ) {
2853                 return LBER_ERROR_MEMORY;
2854         }
2855
2856         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
2857                 parts[1], parts[2] + 1, parts[3] + 1,
2858                 parts[4], parts[5], parts[6] );
2859         normalized->bv_len = 13;
2860
2861         return LDAP_SUCCESS;
2862 }
2863 #endif /* 0 */
2864
2865 static int
2866 utcTimeValidate(
2867         Syntax *syntax,
2868         struct berval *in )
2869 {
2870         int parts[9];
2871         return check_time_syntax(in, 1, parts, NULL);
2872 }
2873
2874 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
2875
2876 static int
2877 generalizedTimeValidate(
2878         Syntax *syntax,
2879         struct berval *in )
2880 {
2881         int parts[9];
2882         struct berval fraction;
2883         return check_time_syntax(in, 0, parts, &fraction);
2884 }
2885
2886 static int
2887 generalizedTimeNormalize(
2888         slap_mask_t usage,
2889         Syntax *syntax,
2890         MatchingRule *mr,
2891         struct berval *val,
2892         struct berval *normalized,
2893         void *ctx )
2894 {
2895         int parts[9], rc;
2896         unsigned int len;
2897         struct berval fraction;
2898
2899         rc = check_time_syntax(val, 0, parts, &fraction);
2900         if (rc != LDAP_SUCCESS) {
2901                 return rc;
2902         }
2903
2904         len = sizeof("YYYYmmddHHMMSSZ")-1 + fraction.bv_len;
2905         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
2906         if ( BER_BVISNULL( normalized ) ) {
2907                 return LBER_ERROR_MEMORY;
2908         }
2909
2910         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
2911                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
2912                 parts[4], parts[5], parts[6] );
2913         if ( !BER_BVISEMPTY( &fraction ) ) {
2914                 memcpy( normalized->bv_val + sizeof("YYYYmmddHHMMSSZ")-2,
2915                         fraction.bv_val, fraction.bv_len );
2916                 normalized->bv_val[sizeof("YYYYmmddHHMMSSZ")-2] = '.';
2917         }
2918         strcpy( normalized->bv_val + len-1, "Z" );
2919         normalized->bv_len = len;
2920
2921         return LDAP_SUCCESS;
2922 }
2923
2924 static int
2925 generalizedTimeOrderingMatch(
2926         int *matchp,
2927         slap_mask_t flags,
2928         Syntax *syntax,
2929         MatchingRule *mr,
2930         struct berval *value,
2931         void *assertedValue )
2932 {
2933         struct berval *asserted = (struct berval *) assertedValue;
2934         ber_len_t v_len  = value->bv_len;
2935         ber_len_t av_len = asserted->bv_len;
2936
2937         /* ignore trailing 'Z' when comparing */
2938         int match = memcmp( value->bv_val, asserted->bv_val,
2939                 (v_len < av_len ? v_len : av_len) - 1 );
2940         if ( match == 0 ) match = v_len - av_len;
2941
2942         *matchp = match;
2943         return LDAP_SUCCESS;
2944 }
2945
2946 /* Index generation function */
2947 int generalizedTimeIndexer(
2948         slap_mask_t use,
2949         slap_mask_t flags,
2950         Syntax *syntax,
2951         MatchingRule *mr,
2952         struct berval *prefix,
2953         BerVarray values,
2954         BerVarray *keysp,
2955         void *ctx )
2956 {
2957         int i, j;
2958         BerVarray keys;
2959         char tmp[5];
2960         BerValue bvtmp; /* 40 bit index */
2961         struct lutil_tm tm;
2962         struct lutil_timet tt;
2963
2964         bvtmp.bv_len = sizeof(tmp);
2965         bvtmp.bv_val = tmp;
2966         for( i=0; values[i].bv_val != NULL; i++ ) {
2967                 /* just count them */
2968         }
2969
2970         /* we should have at least one value at this point */
2971         assert( i > 0 );
2972
2973         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2974
2975         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
2976         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
2977                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
2978                 /* Use 40 bits of time for key */
2979                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
2980                         lutil_tm2time( &tm, &tt );
2981                         tmp[0] = tt.tt_gsec & 0xff;
2982                         tmp[4] = tt.tt_sec & 0xff;
2983                         tt.tt_sec >>= 8;
2984                         tmp[3] = tt.tt_sec & 0xff;
2985                         tt.tt_sec >>= 8;
2986                         tmp[2] = tt.tt_sec & 0xff;
2987                         tt.tt_sec >>= 8;
2988                         tmp[1] = tt.tt_sec & 0xff;
2989                         
2990                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
2991                 }
2992         }
2993
2994         keys[j].bv_val = NULL;
2995         keys[j].bv_len = 0;
2996
2997         *keysp = keys;
2998
2999         return LDAP_SUCCESS;
3000 }
3001
3002 /* Index generation function */
3003 int generalizedTimeFilter(
3004         slap_mask_t use,
3005         slap_mask_t flags,
3006         Syntax *syntax,
3007         MatchingRule *mr,
3008         struct berval *prefix,
3009         void * assertedValue,
3010         BerVarray *keysp,
3011         void *ctx )
3012 {
3013         BerVarray keys;
3014         char tmp[5];
3015         BerValue bvtmp; /* 40 bit index */
3016         BerValue *value = (BerValue *) assertedValue;
3017         struct lutil_tm tm;
3018         struct lutil_timet tt;
3019         
3020         bvtmp.bv_len = sizeof(tmp);
3021         bvtmp.bv_val = tmp;
3022         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
3023         /* Use 40 bits of time for key */
3024         if ( value->bv_val && value->bv_len >= 10 &&
3025                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
3026
3027                 lutil_tm2time( &tm, &tt );
3028                 tmp[0] = tt.tt_gsec & 0xff;
3029                 tmp[4] = tt.tt_sec & 0xff;
3030                 tt.tt_sec >>= 8;
3031                 tmp[3] = tt.tt_sec & 0xff;
3032                 tt.tt_sec >>= 8;
3033                 tmp[2] = tt.tt_sec & 0xff;
3034                 tt.tt_sec >>= 8;
3035                 tmp[1] = tt.tt_sec & 0xff;
3036
3037                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
3038                 ber_dupbv_x(keys, &bvtmp, ctx );
3039                 keys[1].bv_val = NULL;
3040                 keys[1].bv_len = 0;
3041         } else {
3042                 keys = NULL;
3043         }
3044
3045         *keysp = keys;
3046
3047         return LDAP_SUCCESS;
3048 }
3049
3050 static int
3051 deliveryMethodValidate(
3052         Syntax *syntax,
3053         struct berval *val )
3054 {
3055 #undef LENOF
3056 #define LENOF(s) (sizeof(s)-1)
3057         struct berval tmp = *val;
3058         /*
3059      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
3060          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
3061          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
3062          */
3063 again:
3064         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3065
3066         switch( tmp.bv_val[0] ) {
3067         case 'a':
3068         case 'A':
3069                 if(( tmp.bv_len >= LENOF("any") ) &&
3070                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
3071                 {
3072                         tmp.bv_len -= LENOF("any");
3073                         tmp.bv_val += LENOF("any");
3074                         break;
3075                 }
3076                 return LDAP_INVALID_SYNTAX;
3077
3078         case 'm':
3079         case 'M':
3080                 if(( tmp.bv_len >= LENOF("mhs") ) &&
3081                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
3082                 {
3083                         tmp.bv_len -= LENOF("mhs");
3084                         tmp.bv_val += LENOF("mhs");
3085                         break;
3086                 }
3087                 return LDAP_INVALID_SYNTAX;
3088
3089         case 'p':
3090         case 'P':
3091                 if(( tmp.bv_len >= LENOF("physical") ) &&
3092                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
3093                 {
3094                         tmp.bv_len -= LENOF("physical");
3095                         tmp.bv_val += LENOF("physical");
3096                         break;
3097                 }
3098                 return LDAP_INVALID_SYNTAX;
3099
3100         case 't':
3101         case 'T': /* telex or teletex or telephone */
3102                 if(( tmp.bv_len >= LENOF("telex") ) &&
3103                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
3104                 {
3105                         tmp.bv_len -= LENOF("telex");
3106                         tmp.bv_val += LENOF("telex");
3107                         break;
3108                 }
3109                 if(( tmp.bv_len >= LENOF("teletex") ) &&
3110                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
3111                 {
3112                         tmp.bv_len -= LENOF("teletex");
3113                         tmp.bv_val += LENOF("teletex");
3114                         break;
3115                 }
3116                 if(( tmp.bv_len >= LENOF("telephone") ) &&
3117                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
3118                 {
3119                         tmp.bv_len -= LENOF("telephone");
3120                         tmp.bv_val += LENOF("telephone");
3121                         break;
3122                 }
3123                 return LDAP_INVALID_SYNTAX;
3124
3125         case 'g':
3126         case 'G': /* g3fax or g4fax */
3127                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
3128                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
3129                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
3130                 {
3131                         tmp.bv_len -= LENOF("g3fax");
3132                         tmp.bv_val += LENOF("g3fax");
3133                         break;
3134                 }
3135                 return LDAP_INVALID_SYNTAX;
3136
3137         case 'i':
3138         case 'I':
3139                 if(( tmp.bv_len >= LENOF("ia5") ) &&
3140                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
3141                 {
3142                         tmp.bv_len -= LENOF("ia5");
3143                         tmp.bv_val += LENOF("ia5");
3144                         break;
3145                 }
3146                 return LDAP_INVALID_SYNTAX;
3147
3148         case 'v':
3149         case 'V':
3150                 if(( tmp.bv_len >= LENOF("videotex") ) &&
3151                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
3152                 {
3153                         tmp.bv_len -= LENOF("videotex");
3154                         tmp.bv_val += LENOF("videotex");
3155                         break;
3156                 }
3157                 return LDAP_INVALID_SYNTAX;
3158
3159         default:
3160                 return LDAP_INVALID_SYNTAX;
3161         }
3162
3163         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
3164
3165         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3166                 tmp.bv_len++;
3167                 tmp.bv_val--;
3168         }
3169         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
3170                 tmp.bv_len++;
3171                 tmp.bv_val--;
3172         } else {
3173                 return LDAP_INVALID_SYNTAX;
3174         }
3175         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3176                 tmp.bv_len++;
3177                 tmp.bv_val--;
3178         }
3179
3180         goto again;
3181 }
3182
3183 static int
3184 nisNetgroupTripleValidate(
3185         Syntax *syntax,
3186         struct berval *val )
3187 {
3188         char *p, *e;
3189         int commas = 0;
3190
3191         if ( BER_BVISEMPTY( val ) ) {
3192                 return LDAP_INVALID_SYNTAX;
3193         }
3194
3195         p = (char *)val->bv_val;
3196         e = p + val->bv_len;
3197
3198         if ( *p != '(' /*')'*/ ) {
3199                 return LDAP_INVALID_SYNTAX;
3200         }
3201
3202         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
3203                 if ( *p == ',' ) {
3204                         commas++;
3205                         if ( commas > 2 ) {
3206                                 return LDAP_INVALID_SYNTAX;
3207                         }
3208
3209                 } else if ( !AD_CHAR( *p ) ) {
3210                         return LDAP_INVALID_SYNTAX;
3211                 }
3212         }
3213
3214         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
3215                 return LDAP_INVALID_SYNTAX;
3216         }
3217
3218         p++;
3219
3220         if (p != e) {
3221                 return LDAP_INVALID_SYNTAX;
3222         }
3223
3224         return LDAP_SUCCESS;
3225 }
3226
3227 static int
3228 bootParameterValidate(
3229         Syntax *syntax,
3230         struct berval *val )
3231 {
3232         char *p, *e;
3233
3234         if ( BER_BVISEMPTY( val ) ) {
3235                 return LDAP_INVALID_SYNTAX;
3236         }
3237
3238         p = (char *)val->bv_val;
3239         e = p + val->bv_len;
3240
3241         /* key */
3242         for (; ( p < e ) && ( *p != '=' ); p++ ) {
3243                 if ( !AD_CHAR( *p ) ) {
3244                         return LDAP_INVALID_SYNTAX;
3245                 }
3246         }
3247
3248         if ( *p != '=' ) {
3249                 return LDAP_INVALID_SYNTAX;
3250         }
3251
3252         /* server */
3253         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
3254                 if ( !AD_CHAR( *p ) ) {
3255                         return LDAP_INVALID_SYNTAX;
3256                 }
3257         }
3258
3259         if ( *p != ':' ) {
3260                 return LDAP_INVALID_SYNTAX;
3261         }
3262
3263         /* path */
3264         for ( p++; p < e; p++ ) {
3265                 if ( !SLAP_PRINTABLE( *p ) ) {
3266                         return LDAP_INVALID_SYNTAX;
3267                 }
3268         }
3269
3270         return LDAP_SUCCESS;
3271 }
3272
3273 static int
3274 firstComponentNormalize(
3275         slap_mask_t usage,
3276         Syntax *syntax,
3277         MatchingRule *mr,
3278         struct berval *val,
3279         struct berval *normalized,
3280         void *ctx )
3281 {
3282         int rc;
3283         struct berval comp;
3284         ber_len_t len;
3285
3286         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
3287                 ber_dupbv_x( normalized, val, ctx );
3288                 return LDAP_SUCCESS;
3289         }
3290
3291         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3292
3293         if( val->bv_val[0] != '(' /*')'*/ &&
3294                 val->bv_val[0] != '{' /*'}'*/ )
3295         {
3296                 return LDAP_INVALID_SYNTAX;
3297         }
3298
3299         /* trim leading white space */
3300         for( len=1;
3301                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
3302                 len++ )
3303         {
3304                 /* empty */
3305         }
3306
3307         /* grab next word */
3308         comp.bv_val = &val->bv_val[len];
3309         len = val->bv_len - len;
3310         for( comp.bv_len = 0;
3311                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
3312                 comp.bv_len++ )
3313         {
3314                 /* empty */
3315         }
3316
3317         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
3318                 rc = numericoidValidate( NULL, &comp );
3319         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
3320                 rc = integerValidate( NULL, &comp );
3321         } else {
3322                 rc = LDAP_INVALID_SYNTAX;
3323         }
3324         
3325
3326         if( rc == LDAP_SUCCESS ) {
3327                 ber_dupbv_x( normalized, &comp, ctx );
3328         }
3329
3330         return rc;
3331 }
3332
3333
3334 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
3335 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
3336
3337 static slap_syntax_defs_rec syntax_defs[] = {
3338         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
3339                 X_BINARY X_NOT_H_R ")",
3340                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL},
3341         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
3342                 0, NULL, NULL},
3343         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
3344                 0, NULL, NULL},
3345         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
3346                 X_NOT_H_R ")",
3347                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3348         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
3349                 X_NOT_H_R ")",
3350                 SLAP_SYNTAX_BER, berValidate, NULL},
3351         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
3352                 0, bitStringValidate, NULL },
3353         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
3354                 0, booleanValidate, NULL},
3355         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
3356                 X_BINARY X_NOT_H_R ")",
3357                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, certificateValidate, NULL},
3358         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
3359                 X_BINARY X_NOT_H_R ")",
3360                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3361         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
3362                 X_BINARY X_NOT_H_R ")",
3363                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3364         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
3365                 0, countryStringValidate, NULL},
3366         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
3367                 0, dnValidate, dnPretty},
3368         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
3369                 0, rdnValidate, rdnPretty},
3370 #ifdef LDAP_COMP_MATCH
3371         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
3372                 0, allComponentsValidate, NULL},
3373         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
3374                 0, componentFilterValidate, NULL},
3375 #endif
3376         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
3377                 0, NULL, NULL},
3378         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
3379                 0, deliveryMethodValidate, NULL},
3380         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
3381                 0, UTF8StringValidate, NULL},
3382         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
3383                 0, NULL, NULL},
3384         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
3385                 0, NULL, NULL},
3386         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
3387                 0, NULL, NULL},
3388         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
3389                 0, NULL, NULL},
3390         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
3391                 0, NULL, NULL},
3392         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
3393                 0, printablesStringValidate, NULL},
3394         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
3395                 SLAP_SYNTAX_BLOB, NULL, NULL},
3396         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
3397                 0, generalizedTimeValidate, NULL},
3398         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
3399                 0, NULL, NULL},
3400         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
3401                 0, IA5StringValidate, NULL},
3402         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
3403                 0, integerValidate, NULL},
3404         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
3405                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3406         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
3407                 0, NULL, NULL},
3408         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
3409                 0, NULL, NULL},
3410         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
3411                 0, NULL, NULL},
3412         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
3413                 0, NULL, NULL},
3414         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
3415                 0, NULL, NULL},
3416         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
3417                 0, nameUIDValidate, nameUIDPretty },
3418         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
3419                 0, NULL, NULL},
3420         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
3421                 0, numericStringValidate, NULL},
3422         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
3423                 0, NULL, NULL},
3424         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
3425                 0, numericoidValidate, NULL},
3426         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
3427                 0, IA5StringValidate, NULL},
3428         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
3429                 0, blobValidate, NULL},
3430         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
3431                 0, UTF8StringValidate, NULL},
3432         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
3433                 0, NULL, NULL},
3434         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
3435                 0, NULL, NULL},
3436         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
3437                 0, printableStringValidate, NULL},
3438         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
3439 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
3440                 0, subtreeSpecificationValidate, NULL},
3441         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
3442                 X_BINARY X_NOT_H_R ")",
3443                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
3444         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
3445                 0, printableStringValidate, NULL},
3446         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
3447                 0, NULL, NULL},
3448         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
3449                 0, printablesStringValidate, NULL},
3450 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3451         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
3452                 0, utcTimeValidate, NULL},
3453 #endif
3454         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
3455                 0, NULL, NULL},
3456         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
3457                 0, NULL, NULL},
3458         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
3459                 0, NULL, NULL},
3460         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
3461                 0, NULL, NULL},
3462         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
3463                 0, NULL, NULL},
3464
3465         /* RFC 2307 NIS Syntaxes */
3466         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
3467                 0, nisNetgroupTripleValidate, NULL},
3468         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
3469                 0, bootParameterValidate, NULL},
3470
3471         /* From PKIX *//* This OID is not published yet. */
3472         {"( 1.2.826.0.1.3344810.7.1 DESC 'Certificate Serial Number and Issuer' )",
3473                 SLAP_SYNTAX_HIDE,
3474                 serialNumberAndIssuerValidate,
3475                 serialNumberAndIssuerPretty},
3476
3477 #ifdef SLAPD_AUTHPASSWD
3478         /* needs updating */
3479         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
3480                 SLAP_SYNTAX_HIDE, NULL, NULL},
3481 #endif
3482
3483         {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
3484                 0, UUIDValidate, UUIDPretty},
3485
3486         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
3487                 SLAP_SYNTAX_HIDE, csnValidate, NULL},
3488
3489         /* OpenLDAP Void Syntax */
3490         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
3491                 SLAP_SYNTAX_HIDE, inValidate, NULL},
3492
3493 #ifdef SLAP_AUTHZ_SYNTAX
3494         /* FIXME: OID is unused, but not registered yet */
3495         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
3496                 SLAP_SYNTAX_HIDE, authzValidate, authzPretty},
3497 #endif /* SLAP_AUTHZ_SYNTAX */
3498
3499         {NULL, 0, NULL, NULL}
3500 };
3501
3502 char *certificateExactMatchSyntaxes[] = {
3503         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
3504         NULL
3505 };
3506 #ifdef LDAP_COMP_MATCH
3507 char *componentFilterMatchSyntaxes[] = {
3508         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
3509         NULL
3510 };
3511 #endif
3512 char *directoryStringSyntaxes[] = {
3513         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
3514         NULL
3515 };
3516 char *integerFirstComponentMatchSyntaxes[] = {
3517         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
3518         "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
3519         NULL
3520 };
3521 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
3522         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
3523         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
3524         "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
3525         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
3526         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
3527         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
3528         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
3529         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
3530         NULL
3531 };
3532
3533 /*
3534  * Other matching rules in X.520 that we do not use (yet):
3535  *
3536  * 2.5.13.25    uTCTimeMatch
3537  * 2.5.13.26    uTCTimeOrderingMatch
3538  * 2.5.13.31*   directoryStringFirstComponentMatch
3539  * 2.5.13.32*   wordMatch
3540  * 2.5.13.33*   keywordMatch
3541  * 2.5.13.36    certificatePairExactMatch
3542  * 2.5.13.37    certificatePairMatch
3543  * 2.5.13.38    certificateListExactMatch
3544  * 2.5.13.39    certificateListMatch
3545  * 2.5.13.40    algorithmIdentifierMatch
3546  * 2.5.13.41*   storedPrefixMatch
3547  * 2.5.13.42    attributeCertificateMatch
3548  * 2.5.13.43    readerAndKeyIDMatch
3549  * 2.5.13.44    attributeIntegrityMatch
3550  *
3551  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
3552  */
3553 static slap_mrule_defs_rec mrule_defs[] = {
3554         /*
3555          * EQUALITY matching rules must be listed after associated APPROX
3556          * matching rules.  So, we list all APPROX matching rules first.
3557          */
3558         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
3559                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3560                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3561                 NULL, NULL, directoryStringApproxMatch,
3562                 directoryStringApproxIndexer, directoryStringApproxFilter,
3563                 NULL},
3564
3565         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
3566                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3567                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3568                 NULL, NULL, IA5StringApproxMatch,
3569                 IA5StringApproxIndexer, IA5StringApproxFilter,
3570                 NULL},
3571
3572         /*
3573          * Other matching rules
3574          */
3575         
3576         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
3577                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3578                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3579                 NULL, NULL, octetStringMatch,
3580                 octetStringIndexer, octetStringFilter,
3581                 NULL },
3582
3583         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
3584                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3585                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3586                 NULL, dnNormalize, dnMatch,
3587                 octetStringIndexer, octetStringFilter,
3588                 NULL },
3589
3590         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
3591                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3592                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3593                 NULL, dnNormalize, dnRelativeMatch,
3594                 NULL, NULL,
3595                 NULL },
3596
3597         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
3598                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3599                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3600                 NULL, dnNormalize, dnRelativeMatch,
3601                 NULL, NULL,
3602                 NULL },
3603
3604         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
3605                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3606                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3607                 NULL, dnNormalize, dnRelativeMatch,
3608                 NULL, NULL,
3609                 NULL },
3610
3611         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
3612                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3613                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3614                 NULL, dnNormalize, dnRelativeMatch,
3615                 NULL, NULL,
3616                 NULL },
3617
3618         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
3619                 "SYNTAX 1.2.36.79672281.1.5.0 )",
3620                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3621                 NULL, rdnNormalize, rdnMatch,
3622                 octetStringIndexer, octetStringFilter,
3623                 NULL },
3624
3625 #ifdef LDAP_COMP_MATCH
3626         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
3627                 "SYNTAX 1.2.36.79672281.1.5.2 )",
3628                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
3629                 NULL, NULL , componentFilterMatch,
3630                 octetStringIndexer, octetStringFilter,
3631                 NULL },
3632
3633         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
3634                 "SYNTAX 1.2.36.79672281.1.5.3 )",
3635                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
3636                 NULL, NULL , allComponentsMatch,
3637                 octetStringIndexer, octetStringFilter,
3638                 NULL },
3639
3640         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
3641                 "SYNTAX 1.2.36.79672281.1.5.3 )",
3642                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
3643                 NULL, NULL , directoryComponentsMatch,
3644                 octetStringIndexer, octetStringFilter,
3645                 NULL },
3646 #endif
3647
3648         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
3649                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3650                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3651                 NULL, UTF8StringNormalize, octetStringMatch,
3652                 octetStringIndexer, octetStringFilter,
3653                 directoryStringApproxMatchOID },
3654
3655         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
3656                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3657                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3658                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3659                 NULL, NULL,
3660                 "caseIgnoreMatch" },
3661
3662         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
3663                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3664                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3665                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
3666                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3667                 "caseIgnoreMatch" },
3668
3669         {"( 2.5.13.5 NAME 'caseExactMatch' "
3670                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3671                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3672                 NULL, UTF8StringNormalize, octetStringMatch,
3673                 octetStringIndexer, octetStringFilter,
3674                 directoryStringApproxMatchOID },
3675
3676         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
3677                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3678                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3679                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3680                 NULL, NULL,
3681                 "caseExactMatch" },
3682
3683         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
3684                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3685                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3686                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
3687                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3688                 "caseExactMatch" },
3689
3690         {"( 2.5.13.8 NAME 'numericStringMatch' "
3691                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3692                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3693                 NULL, numericStringNormalize, octetStringMatch,
3694                 octetStringIndexer, octetStringFilter,
3695                 NULL },
3696
3697         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
3698                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3699                 SLAP_MR_ORDERING, NULL,
3700                 NULL, numericStringNormalize, octetStringOrderingMatch,
3701                 NULL, NULL,
3702                 "numericStringMatch" },
3703
3704         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
3705                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3706                 SLAP_MR_SUBSTR, NULL,
3707                 NULL, numericStringNormalize, octetStringSubstringsMatch,
3708                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3709                 "numericStringMatch" },
3710
3711         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
3712                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
3713                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3714                 NULL, NULL, NULL, NULL, NULL, NULL },
3715
3716         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
3717                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3718                 SLAP_MR_SUBSTR, NULL,
3719                 NULL, NULL, NULL, NULL, NULL,
3720                 "caseIgnoreListMatch" },
3721
3722         {"( 2.5.13.13 NAME 'booleanMatch' "
3723                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
3724                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3725                 NULL, NULL, booleanMatch,
3726                 octetStringIndexer, octetStringFilter,
3727                 NULL },
3728
3729         {"( 2.5.13.14 NAME 'integerMatch' "
3730                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3731                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3732                 NULL, NULL, integerMatch,
3733                 octetStringIndexer, octetStringFilter,
3734                 NULL },
3735
3736         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
3737                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3738                 SLAP_MR_ORDERING, NULL,
3739                 NULL, NULL, integerMatch,
3740                 NULL, NULL,
3741                 "integerMatch" },
3742
3743         {"( 2.5.13.16 NAME 'bitStringMatch' "
3744                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
3745                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3746                 NULL, NULL, octetStringMatch,
3747                 octetStringIndexer, octetStringFilter,
3748                 NULL },
3749
3750         {"( 2.5.13.17 NAME 'octetStringMatch' "
3751                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3752                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3753                 NULL, NULL, octetStringMatch,
3754                 octetStringIndexer, octetStringFilter,
3755                 NULL },
3756
3757         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
3758                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3759                 SLAP_MR_ORDERING, NULL,
3760                 NULL, NULL, octetStringOrderingMatch,
3761                 NULL, NULL,
3762                 "octetStringMatch" },
3763
3764         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
3765                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3766                 SLAP_MR_SUBSTR, NULL,
3767                 NULL, NULL, octetStringSubstringsMatch,
3768                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3769                 "octetStringMatch" },
3770
3771         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
3772                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
3773                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3774                 NULL,
3775                 telephoneNumberNormalize, octetStringMatch,
3776                 octetStringIndexer, octetStringFilter,
3777                 NULL },
3778
3779         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
3780                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3781                 SLAP_MR_SUBSTR, NULL,
3782                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
3783                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3784                 "telephoneNumberMatch" },
3785
3786         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
3787                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
3788                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3789                 NULL, NULL, NULL, NULL, NULL, NULL },
3790
3791         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
3792                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
3793                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3794                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
3795                 uniqueMemberIndexer, uniqueMemberFilter,
3796                 NULL },
3797
3798         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
3799                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
3800                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3801                 NULL, NULL, NULL, NULL, NULL, NULL },
3802
3803         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
3804                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3805                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
3806                 NULL, generalizedTimeNormalize, octetStringMatch,
3807                 generalizedTimeIndexer, generalizedTimeFilter,
3808                 NULL },
3809
3810         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
3811                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3812                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
3813                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
3814                 NULL, NULL,
3815                 "generalizedTimeMatch" },
3816
3817         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
3818                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3819                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3820                         integerFirstComponentMatchSyntaxes,
3821                 NULL, firstComponentNormalize, integerMatch,
3822                 octetStringIndexer, octetStringFilter,
3823                 NULL },
3824
3825         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
3826                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3827                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3828                         objectIdentifierFirstComponentMatchSyntaxes,
3829                 NULL, firstComponentNormalize, octetStringMatch,
3830                 octetStringIndexer, octetStringFilter,
3831                 NULL },
3832
3833         {"( 2.5.13.34 NAME 'certificateExactMatch' "
3834                 "SYNTAX 1.2.826.0.1.3344810.7.1 )",
3835                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
3836 #ifdef HAVE_TLS
3837                 NULL, certificateExactNormalize, octetStringMatch,
3838                 octetStringIndexer, octetStringFilter,
3839 #else
3840                 NULL, NULL, NULL, NULL, NULL,
3841 #endif
3842                 NULL },
3843
3844         {"( 2.5.13.35 NAME 'certificateMatch' "
3845                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )",
3846                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3847 #ifdef HAVE_TLS
3848                 NULL, NULL, octetStringMatch,
3849                 octetStringIndexer, octetStringFilter,
3850 #else
3851                 NULL, NULL, NULL, NULL, NULL,
3852 #endif
3853                 NULL },
3854
3855         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
3856                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3857                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3858                 NULL, IA5StringNormalize, octetStringMatch,
3859                 octetStringIndexer, octetStringFilter,
3860                 IA5StringApproxMatchOID },
3861
3862         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
3863                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3864                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3865                 NULL, IA5StringNormalize, octetStringMatch,
3866                 octetStringIndexer, octetStringFilter,
3867                 IA5StringApproxMatchOID },
3868
3869         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
3870                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3871                 SLAP_MR_SUBSTR, NULL,
3872                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
3873                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3874                 "caseIgnoreIA5Match" },
3875
3876         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
3877                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3878                 SLAP_MR_SUBSTR, NULL,
3879                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
3880                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3881                 "caseExactIA5Match" },
3882
3883 #ifdef SLAPD_AUTHPASSWD
3884         /* needs updating */
3885         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
3886                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3887                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3888                 NULL, NULL, authPasswordMatch,
3889                 NULL, NULL,
3890                 NULL},
3891 #endif
3892
3893         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
3894                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3895                 SLAP_MR_EXT, NULL,
3896                 NULL, NULL, integerBitAndMatch,
3897                 NULL, NULL,
3898                 "integerMatch" },
3899
3900         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
3901                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3902                 SLAP_MR_EXT, NULL,
3903                 NULL, NULL, integerBitOrMatch,
3904                 NULL, NULL,
3905                 "integerMatch" },
3906
3907         {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
3908                 "SYNTAX 1.3.6.1.1.16.1 )",
3909                 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
3910                 NULL, UUIDNormalize, octetStringMatch,
3911                 octetStringIndexer, octetStringFilter,
3912                 NULL},
3913
3914         {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
3915                 "SYNTAX 1.3.6.1.1.16.1 )",
3916                 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
3917                 NULL, UUIDNormalize, octetStringOrderingMatch,
3918                 octetStringIndexer, octetStringFilter,
3919                 "UUIDMatch"},
3920
3921         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
3922                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
3923                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
3924                 NULL, NULL, csnMatch,
3925                 csnIndexer, csnFilter,
3926                 NULL},
3927
3928         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
3929                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
3930                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
3931                 NULL, NULL, csnOrderingMatch,
3932                 NULL, NULL,
3933                 "CSNMatch" },
3934
3935 #ifdef SLAP_AUTHZ_SYNTAX
3936         /* FIXME: OID is unused, but not registered yet */
3937         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
3938                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
3939                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3940                 NULL, authzNormalize, authzMatch,
3941                 NULL, NULL,
3942                 NULL},
3943 #endif /* SLAP_AUTHZ_SYNTAX */
3944
3945         {NULL, SLAP_MR_NONE, NULL,
3946                 NULL, NULL, NULL, NULL, NULL,
3947                 NULL }
3948 };
3949
3950 int
3951 slap_schema_init( void )
3952 {
3953         int             res;
3954         int             i;
3955
3956         /* we should only be called once (from main) */
3957         assert( schema_init_done == 0 );
3958
3959         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
3960                 res = register_syntax( &syntax_defs[i] );
3961
3962                 if ( res ) {
3963                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
3964                                  syntax_defs[i].sd_desc );
3965                         return LDAP_OTHER;
3966                 }
3967         }
3968
3969         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
3970                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
3971                         mrule_defs[i].mrd_compat_syntaxes == NULL )
3972                 {
3973                         fprintf( stderr,
3974                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
3975                                  mrule_defs[i].mrd_desc );
3976                         continue;
3977                 }
3978
3979                 res = register_matching_rule( &mrule_defs[i] );
3980
3981                 if ( res ) {
3982                         fprintf( stderr,
3983                                 "slap_schema_init: Error registering matching rule %s\n",
3984                                  mrule_defs[i].mrd_desc );
3985                         return LDAP_OTHER;
3986                 }
3987         }
3988
3989         res = slap_schema_load();
3990         schema_init_done = 1;
3991         return res;
3992 }
3993
3994 void
3995 schema_destroy( void )
3996 {
3997         oidm_destroy();
3998         oc_destroy();
3999         at_destroy();
4000         mr_destroy();
4001         mru_destroy();
4002         syn_destroy();
4003
4004         if( schema_init_done ) {
4005                 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
4006                 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
4007         }
4008 }