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