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