]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
Silence valgrind warnings
[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 = BER_BVNULL;
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                 valueDN = *value;
1091
1092                 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1093                 if ( !BER_BVISNULL( &valueUID ) ) {
1094                         valueUID.bv_val++;
1095                         valueUID.bv_len = valueDN.bv_len
1096                                 - ( valueUID.bv_val - valueDN.bv_val );
1097
1098                         if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1099                                 valueDN.bv_len -= valueUID.bv_len + 1;
1100
1101                         } else {
1102                                 BER_BVZERO( &valueUID );
1103                         }
1104                 }
1105         }
1106
1107         if( valueUID.bv_len && assertedUID.bv_len ) {
1108                 match = valueUID.bv_len - assertedUID.bv_len;
1109                 if ( match ) {
1110                         *matchp = match;
1111                         return LDAP_SUCCESS;
1112                 }
1113
1114                 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1115                 if( match ) {
1116                         *matchp = match;
1117                         return LDAP_SUCCESS;
1118                 }
1119
1120         } else if ( !approx && valueUID.bv_len ) {
1121                 match = -1;
1122                 *matchp = match;
1123                 return LDAP_SUCCESS;
1124
1125         } else if ( !approx && assertedUID.bv_len ) {
1126                 match = 1;
1127                 *matchp = match;
1128                 return LDAP_SUCCESS;
1129         }
1130
1131         return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1132 }
1133
1134 static int 
1135 uniqueMemberIndexer(
1136         slap_mask_t use,
1137         slap_mask_t flags,
1138         Syntax *syntax,
1139         MatchingRule *mr,
1140         struct berval *prefix,
1141         BerVarray values,
1142         BerVarray *keysp,
1143         void *ctx )
1144 {
1145         BerVarray dnvalues;
1146         int rc;
1147         int i;
1148         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1149                 /* just count them */                 
1150         }
1151         assert( i > 0 );
1152
1153         dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1154
1155         for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1156                 struct berval assertedDN = values[i];
1157                 struct berval assertedUID = BER_BVNULL;
1158
1159                 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1160                         assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1161                         if ( !BER_BVISNULL( &assertedUID ) ) {
1162                                 assertedUID.bv_val++;
1163                                 assertedUID.bv_len = assertedDN.bv_len
1164                                         - ( assertedUID.bv_val - assertedDN.bv_val );
1165         
1166                                 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1167                                         assertedDN.bv_len -= assertedUID.bv_len + 1;
1168
1169                                 } else {
1170                                         BER_BVZERO( &assertedUID );
1171                                 }
1172                         }
1173                 }
1174
1175                 dnvalues[i] = assertedDN;
1176         }
1177         BER_BVZERO( &dnvalues[i] );
1178
1179         rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1180                 dnvalues, keysp, ctx );
1181
1182         slap_sl_free( dnvalues, ctx );
1183         return rc;
1184 }
1185
1186 static int 
1187 uniqueMemberFilter(
1188         slap_mask_t use,
1189         slap_mask_t flags,
1190         Syntax *syntax,
1191         MatchingRule *mr,
1192         struct berval *prefix,
1193         void * assertedValue,
1194         BerVarray *keysp,
1195         void *ctx )
1196 {
1197         struct berval *asserted = (struct berval *) assertedValue;
1198         struct berval assertedDN = *asserted;
1199         struct berval assertedUID = BER_BVNULL;
1200
1201         if ( !BER_BVISEMPTY( asserted ) ) {
1202                 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1203                 if ( !BER_BVISNULL( &assertedUID ) ) {
1204                         assertedUID.bv_val++;
1205                         assertedUID.bv_len = assertedDN.bv_len
1206                                 - ( assertedUID.bv_val - assertedDN.bv_val );
1207
1208                         if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1209                                 assertedDN.bv_len -= assertedUID.bv_len + 1;
1210
1211                         } else {
1212                                 BER_BVZERO( &assertedUID );
1213                         }
1214                 }
1215         }
1216
1217         return octetStringFilter( use, flags, syntax, mr, prefix,
1218                 &assertedDN, keysp, ctx );
1219 }
1220
1221
1222 /*
1223  * Handling boolean syntax and matching is quite rigid.
1224  * A more flexible approach would be to allow a variety
1225  * of strings to be normalized and prettied into TRUE
1226  * and FALSE.
1227  */
1228 static int
1229 booleanValidate(
1230         Syntax *syntax,
1231         struct berval *in )
1232 {
1233         /* very unforgiving validation, requires no normalization
1234          * before simplistic matching
1235          */
1236
1237         if( in->bv_len == 4 ) {
1238                 if( bvmatch( in, &slap_true_bv ) ) {
1239                         return LDAP_SUCCESS;
1240                 }
1241         } else if( in->bv_len == 5 ) {
1242                 if( bvmatch( in, &slap_false_bv ) ) {
1243                         return LDAP_SUCCESS;
1244                 }
1245         }
1246
1247         return LDAP_INVALID_SYNTAX;
1248 }
1249
1250 static int
1251 booleanMatch(
1252         int *matchp,
1253         slap_mask_t flags,
1254         Syntax *syntax,
1255         MatchingRule *mr,
1256         struct berval *value,
1257         void *assertedValue )
1258 {
1259         /* simplistic matching allowed by rigid validation */
1260         struct berval *asserted = (struct berval *) assertedValue;
1261         *matchp = value->bv_len != asserted->bv_len;
1262         return LDAP_SUCCESS;
1263 }
1264
1265 /*-------------------------------------------------------------------
1266 LDAP/X.500 string syntax / matching rules have a few oddities.  This
1267 comment attempts to detail how slapd(8) treats them.
1268
1269 Summary:
1270   StringSyntax          X.500   LDAP    Matching/Comments
1271   DirectoryString       CHOICE  UTF8    i/e + ignore insignificant spaces
1272   PrintableString       subset  subset  i/e + ignore insignificant spaces
1273   PrintableString       subset  subset  i/e + ignore insignificant spaces
1274   NumericString         subset  subset  ignore all spaces
1275   IA5String                     ASCII   ASCII   i/e + ignore insignificant spaces
1276   TeletexString         T.61    T.61    i/e + ignore insignificant spaces
1277
1278   TelephoneNumber       subset  subset  i + ignore all spaces and "-"
1279
1280   See draft-ietf-ldapbis-strpro for details (once published).
1281
1282
1283 Directory String -
1284   In X.500(93), a directory string can be either a PrintableString,
1285   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1286   In later versions, more CHOICEs were added.  In all cases the string
1287   must be non-empty.
1288
1289   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1290   A directory string cannot be zero length.
1291
1292   For matching, there are both case ignore and exact rules.  Both
1293   also require that "insignificant" spaces be ignored.
1294         spaces before the first non-space are ignored;
1295         spaces after the last non-space are ignored;
1296         spaces after a space are ignored.
1297   Note: by these rules (and as clarified in X.520), a string of only
1298   spaces is to be treated as if held one space, not empty (which
1299   would be a syntax error).
1300
1301 NumericString
1302   In ASN.1, numeric string is just a string of digits and spaces
1303   and could be empty.  However, in X.500, all attribute values of
1304   numeric string carry a non-empty constraint.  For example:
1305
1306         internationalISDNNumber ATTRIBUTE ::= {
1307                 WITH SYNTAX InternationalISDNNumber
1308                 EQUALITY MATCHING RULE numericStringMatch
1309                 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1310                 ID id-at-internationalISDNNumber }
1311         InternationalISDNNumber ::=
1312             NumericString (SIZE(1..ub-international-isdn-number))
1313
1314   Unforunately, some assertion values are don't carry the same
1315   constraint (but its unclear how such an assertion could ever
1316   be true). In LDAP, there is one syntax (numericString) not two
1317   (numericString with constraint, numericString without constraint).
1318   This should be treated as numericString with non-empty constraint.
1319   Note that while someone may have no ISDN number, there are no ISDN
1320   numbers which are zero length.
1321
1322   In matching, spaces are ignored.
1323
1324 PrintableString
1325   In ASN.1, Printable string is just a string of printable characters
1326   and can be empty.  In X.500, semantics much like NumericString (see
1327   serialNumber for a like example) excepting uses insignificant space
1328   handling instead of ignore all spaces.  
1329
1330 IA5String
1331   Basically same as PrintableString.  There are no examples in X.500,
1332   but same logic applies.  So we require them to be non-empty as
1333   well.
1334
1335 -------------------------------------------------------------------*/
1336
1337 static int
1338 UTF8StringValidate(
1339         Syntax *syntax,
1340         struct berval *in )
1341 {
1342         ber_len_t count;
1343         int len;
1344         unsigned char *u = (unsigned char *)in->bv_val;
1345
1346         if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1347                 /* directory strings cannot be empty */
1348                 return LDAP_INVALID_SYNTAX;
1349         }
1350
1351         for( count = in->bv_len; count > 0; count -= len, u += len ) {
1352                 /* get the length indicated by the first byte */
1353                 len = LDAP_UTF8_CHARLEN2( u, len );
1354
1355                 /* very basic checks */
1356                 switch( len ) {
1357                         case 6:
1358                                 if( (u[5] & 0xC0) != 0x80 ) {
1359                                         return LDAP_INVALID_SYNTAX;
1360                                 }
1361                         case 5:
1362                                 if( (u[4] & 0xC0) != 0x80 ) {
1363                                         return LDAP_INVALID_SYNTAX;
1364                                 }
1365                         case 4:
1366                                 if( (u[3] & 0xC0) != 0x80 ) {
1367                                         return LDAP_INVALID_SYNTAX;
1368                                 }
1369                         case 3:
1370                                 if( (u[2] & 0xC0 )!= 0x80 ) {
1371                                         return LDAP_INVALID_SYNTAX;
1372                                 }
1373                         case 2:
1374                                 if( (u[1] & 0xC0) != 0x80 ) {
1375                                         return LDAP_INVALID_SYNTAX;
1376                                 }
1377                         case 1:
1378                                 /* CHARLEN already validated it */
1379                                 break;
1380                         default:
1381                                 return LDAP_INVALID_SYNTAX;
1382                 }
1383
1384                 /* make sure len corresponds with the offset
1385                         to the next character */
1386                 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1387         }
1388
1389         if( count != 0 ) {
1390                 return LDAP_INVALID_SYNTAX;
1391         }
1392
1393         return LDAP_SUCCESS;
1394 }
1395
1396 static int
1397 UTF8StringNormalize(
1398         slap_mask_t use,
1399         Syntax *syntax,
1400         MatchingRule *mr,
1401         struct berval *val,
1402         struct berval *normalized,
1403         void *ctx )
1404 {
1405         struct berval tmp, nvalue;
1406         int flags;
1407         int i, wasspace;
1408
1409         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
1410
1411         if( BER_BVISNULL( val ) ) {
1412                 /* assume we're dealing with a syntax (e.g., UTF8String)
1413                  * which allows empty strings
1414                  */
1415                 BER_BVZERO( normalized );
1416                 return LDAP_SUCCESS;
1417         }
1418
1419         flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1420                 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1421         flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1422                 ? LDAP_UTF8_APPROX : 0;
1423
1424         val = UTF8bvnormalize( val, &tmp, flags, ctx );
1425         if( val == NULL ) {
1426                 return LDAP_OTHER;
1427         }
1428         
1429         /* collapse spaces (in place) */
1430         nvalue.bv_len = 0;
1431         nvalue.bv_val = tmp.bv_val;
1432
1433         /* trim leading spaces? */
1434         wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1435                 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1436
1437         for( i = 0; i < tmp.bv_len; i++) {
1438                 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1439                         if( wasspace++ == 0 ) {
1440                                 /* trim repeated spaces */
1441                                 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1442                         }
1443                 } else {
1444                         wasspace = 0;
1445                         nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1446                 }
1447         }
1448
1449         if( !BER_BVISEMPTY( &nvalue ) ) {
1450                 /* trim trailing space? */
1451                 if( wasspace && (
1452                         (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1453                         ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1454                 {
1455                         --nvalue.bv_len;
1456                 }
1457                 nvalue.bv_val[nvalue.bv_len] = '\0';
1458
1459         } else {
1460                 /* string of all spaces is treated as one space */
1461                 nvalue.bv_val[0] = ' ';
1462                 nvalue.bv_val[1] = '\0';
1463                 nvalue.bv_len = 1;
1464         }
1465
1466         *normalized = nvalue;
1467         return LDAP_SUCCESS;
1468 }
1469
1470 static int
1471 directoryStringSubstringsMatch(
1472         int *matchp,
1473         slap_mask_t flags,
1474         Syntax *syntax,
1475         MatchingRule *mr,
1476         struct berval *value,
1477         void *assertedValue )
1478 {
1479         int match = 0;
1480         SubstringsAssertion *sub = assertedValue;
1481         struct berval left = *value;
1482         int i;
1483         int priorspace=0;
1484
1485         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1486                 if ( sub->sa_initial.bv_len > left.bv_len ) {
1487                         /* not enough left */
1488                         match = 1;
1489                         goto done;
1490                 }
1491
1492                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1493                         sub->sa_initial.bv_len );
1494
1495                 if ( match != 0 ) {
1496                         goto done;
1497                 }
1498
1499                 left.bv_val += sub->sa_initial.bv_len;
1500                 left.bv_len -= sub->sa_initial.bv_len;
1501
1502                 priorspace = ASCII_SPACE(
1503                         sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1504         }
1505
1506         if ( sub->sa_any ) {
1507                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1508                         ber_len_t idx;
1509                         char *p;
1510
1511                         if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] ) 
1512                                 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1513                         { 
1514                                 /* allow next space to match */
1515                                 left.bv_val--;
1516                                 left.bv_len++;
1517                         }
1518                         priorspace=0;
1519
1520 retry:
1521                         if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1522                                 continue;
1523                         }
1524
1525                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1526                                 /* not enough left */
1527                                 match = 1;
1528                                 goto done;
1529                         }
1530
1531                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1532
1533                         if( p == NULL ) {
1534                                 match = 1;
1535                                 goto done;
1536                         }
1537
1538                         idx = p - left.bv_val;
1539
1540                         if ( idx >= left.bv_len ) {
1541                                 /* this shouldn't happen */
1542                                 return LDAP_OTHER;
1543                         }
1544
1545                         left.bv_val = p;
1546                         left.bv_len -= idx;
1547
1548                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1549                                 /* not enough left */
1550                                 match = 1;
1551                                 goto done;
1552                         }
1553
1554                         match = memcmp( left.bv_val,
1555                                 sub->sa_any[i].bv_val,
1556                                 sub->sa_any[i].bv_len );
1557
1558                         if ( match != 0 ) {
1559                                 left.bv_val++;
1560                                 left.bv_len--;
1561                                 goto retry;
1562                         }
1563
1564                         left.bv_val += sub->sa_any[i].bv_len;
1565                         left.bv_len -= sub->sa_any[i].bv_len;
1566
1567                         priorspace = ASCII_SPACE(
1568                                 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1569                 }
1570         }
1571
1572         if ( !BER_BVISNULL( &sub->sa_final ) ) {
1573                 if( priorspace && !BER_BVISEMPTY( &sub->sa_final ) 
1574                         && ASCII_SPACE( sub->sa_final.bv_val[0] ))
1575                 { 
1576                         /* allow next space to match */
1577                         left.bv_val--;
1578                         left.bv_len++;
1579                 }
1580
1581                 if ( sub->sa_final.bv_len > left.bv_len ) {
1582                         /* not enough left */
1583                         match = 1;
1584                         goto done;
1585                 }
1586
1587                 match = memcmp( sub->sa_final.bv_val,
1588                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1589                         sub->sa_final.bv_len );
1590
1591                 if ( match != 0 ) {
1592                         goto done;
1593                 }
1594         }
1595
1596 done:
1597         *matchp = match;
1598         return LDAP_SUCCESS;
1599 }
1600
1601 #if defined(SLAPD_APPROX_INITIALS)
1602 #       define SLAPD_APPROX_DELIMITER "._ "
1603 #       define SLAPD_APPROX_WORDLEN 2
1604 #else
1605 #       define SLAPD_APPROX_DELIMITER " "
1606 #       define SLAPD_APPROX_WORDLEN 1
1607 #endif
1608
1609 static int
1610 approxMatch(
1611         int *matchp,
1612         slap_mask_t flags,
1613         Syntax *syntax,
1614         MatchingRule *mr,
1615         struct berval *value,
1616         void *assertedValue )
1617 {
1618         struct berval *nval, *assertv;
1619         char *val, **values, **words, *c;
1620         int i, count, len, nextchunk=0, nextavail=0;
1621
1622         /* Yes, this is necessary */
1623         nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
1624         if( nval == NULL ) {
1625                 *matchp = 1;
1626                 return LDAP_SUCCESS;
1627         }
1628
1629         /* Yes, this is necessary */
1630         assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1631                 NULL, LDAP_UTF8_APPROX, NULL );
1632         if( assertv == NULL ) {
1633                 ber_bvfree( nval );
1634                 *matchp = 1;
1635                 return LDAP_SUCCESS;
1636         }
1637
1638         /* Isolate how many words there are */
1639         for ( c = nval->bv_val, count = 1; *c; c++ ) {
1640                 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1641                 if ( c == NULL ) break;
1642                 *c = '\0';
1643                 count++;
1644         }
1645
1646         /* Get a phonetic copy of each word */
1647         words = (char **)ch_malloc( count * sizeof(char *) );
1648         values = (char **)ch_malloc( count * sizeof(char *) );
1649         for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
1650                 words[i] = c;
1651                 values[i] = phonetic(c);
1652         }
1653
1654         /* Work through the asserted value's words, to see if at least some
1655            of the words are there, in the same order. */
1656         len = 0;
1657         while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1658                 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1659                 if( len == 0 ) {
1660                         nextchunk++;
1661                         continue;
1662                 }
1663 #if defined(SLAPD_APPROX_INITIALS)
1664                 else if( len == 1 ) {
1665                         /* Single letter words need to at least match one word's initial */
1666                         for( i=nextavail; i<count; i++ )
1667                                 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1668                                         nextavail=i+1;
1669                                         break;
1670                                 }
1671                 }
1672 #endif
1673                 else {
1674                         /* Isolate the next word in the asserted value and phonetic it */
1675                         assertv->bv_val[nextchunk+len] = '\0';
1676                         val = phonetic( assertv->bv_val + nextchunk );
1677
1678                         /* See if this phonetic chunk is in the remaining words of *value */
1679                         for( i=nextavail; i<count; i++ ){
1680                                 if( !strcmp( val, values[i] ) ){
1681                                         nextavail = i+1;
1682                                         break;
1683                                 }
1684                         }
1685                         ch_free( val );
1686                 }
1687
1688                 /* This chunk in the asserted value was NOT within the *value. */
1689                 if( i >= count ) {
1690                         nextavail=-1;
1691                         break;
1692                 }
1693
1694                 /* Go on to the next word in the asserted value */
1695                 nextchunk += len+1;
1696         }
1697
1698         /* If some of the words were seen, call it a match */
1699         if( nextavail > 0 ) {
1700                 *matchp = 0;
1701         }
1702         else {
1703                 *matchp = 1;
1704         }
1705
1706         /* Cleanup allocs */
1707         ber_bvfree( assertv );
1708         for( i=0; i<count; i++ ) {
1709                 ch_free( values[i] );
1710         }
1711         ch_free( values );
1712         ch_free( words );
1713         ber_bvfree( nval );
1714
1715         return LDAP_SUCCESS;
1716 }
1717
1718 static int 
1719 approxIndexer(
1720         slap_mask_t use,
1721         slap_mask_t flags,
1722         Syntax *syntax,
1723         MatchingRule *mr,
1724         struct berval *prefix,
1725         BerVarray values,
1726         BerVarray *keysp,
1727         void *ctx )
1728 {
1729         char *c;
1730         int i,j, len, wordcount, keycount=0;
1731         struct berval *newkeys;
1732         BerVarray keys=NULL;
1733
1734         for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
1735                 struct berval val = BER_BVNULL;
1736                 /* Yes, this is necessary */
1737                 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
1738                 assert( !BER_BVISNULL( &val ) );
1739
1740                 /* Isolate how many words there are. There will be a key for each */
1741                 for( wordcount = 0, c = val.bv_val; *c; c++) {
1742                         len = strcspn(c, SLAPD_APPROX_DELIMITER);
1743                         if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1744                         c+= len;
1745                         if (*c == '\0') break;
1746                         *c = '\0';
1747                 }
1748
1749                 /* Allocate/increase storage to account for new keys */
1750                 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
1751                         * sizeof(struct berval) );
1752                 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1753                 if( keys ) ch_free( keys );
1754                 keys = newkeys;
1755
1756                 /* Get a phonetic copy of each word */
1757                 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1758                         len = strlen( c );
1759                         if( len < SLAPD_APPROX_WORDLEN ) continue;
1760                         ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1761                         keycount++;
1762                         i++;
1763                 }
1764
1765                 ber_memfree( val.bv_val );
1766         }
1767         BER_BVZERO( &keys[keycount] );
1768         *keysp = keys;
1769
1770         return LDAP_SUCCESS;
1771 }
1772
1773 static int 
1774 approxFilter(
1775         slap_mask_t use,
1776         slap_mask_t flags,
1777         Syntax *syntax,
1778         MatchingRule *mr,
1779         struct berval *prefix,
1780         void * assertedValue,
1781         BerVarray *keysp,
1782         void *ctx )
1783 {
1784         char *c;
1785         int i, count, len;
1786         struct berval *val;
1787         BerVarray keys;
1788
1789         /* Yes, this is necessary */
1790         val = UTF8bvnormalize( ((struct berval *)assertedValue),
1791                 NULL, LDAP_UTF8_APPROX, NULL );
1792         if( val == NULL || BER_BVISNULL( val ) ) {
1793                 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1794                 BER_BVZERO( &keys[0] );
1795                 *keysp = keys;
1796                 ber_bvfree( val );
1797                 return LDAP_SUCCESS;
1798         }
1799
1800         /* Isolate how many words there are. There will be a key for each */
1801         for( count = 0,c = val->bv_val; *c; c++) {
1802                 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1803                 if( len >= SLAPD_APPROX_WORDLEN ) count++;
1804                 c+= len;
1805                 if (*c == '\0') break;
1806                 *c = '\0';
1807         }
1808
1809         /* Allocate storage for new keys */
1810         keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1811
1812         /* Get a phonetic copy of each word */
1813         for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1814                 len = strlen(c);
1815                 if( len < SLAPD_APPROX_WORDLEN ) continue;
1816                 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1817                 i++;
1818         }
1819
1820         ber_bvfree( val );
1821
1822         BER_BVZERO( &keys[count] );
1823         *keysp = keys;
1824
1825         return LDAP_SUCCESS;
1826 }
1827
1828 /* Remove all spaces and '-' characters */
1829 static int
1830 telephoneNumberNormalize(
1831         slap_mask_t usage,
1832         Syntax *syntax,
1833         MatchingRule *mr,
1834         struct berval *val,
1835         struct berval *normalized,
1836         void *ctx )
1837 {
1838         char *p, *q;
1839
1840         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ));
1841
1842         /* validator should have refused an empty string */
1843         assert( !BER_BVISEMPTY( val ) );
1844
1845         q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
1846
1847         for( p = val->bv_val; *p; p++ ) {
1848                 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1849                         *q++ = *p;
1850                 }
1851         }
1852         *q = '\0';
1853
1854         normalized->bv_len = q - normalized->bv_val;
1855
1856         if( BER_BVISEMPTY( normalized ) ) {
1857                 slap_sl_free( normalized->bv_val, ctx );
1858                 BER_BVZERO( normalized );
1859                 return LDAP_INVALID_SYNTAX;
1860         }
1861
1862         return LDAP_SUCCESS;
1863 }
1864
1865 int
1866 numericoidValidate(
1867         Syntax *syntax,
1868         struct berval *in )
1869 {
1870         struct berval val = *in;
1871
1872         if( BER_BVISEMPTY( &val ) ) {
1873                 /* disallow empty strings */
1874                 return LDAP_INVALID_SYNTAX;
1875         }
1876
1877         while( OID_LEADCHAR( val.bv_val[0] ) ) {
1878                 if ( val.bv_len == 1 ) {
1879                         return LDAP_SUCCESS;
1880                 }
1881
1882                 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
1883                         break;
1884                 }
1885
1886                 val.bv_val++;
1887                 val.bv_len--;
1888
1889                 while ( OID_LEADCHAR( val.bv_val[0] )) {
1890                         val.bv_val++;
1891                         val.bv_len--;
1892
1893                         if ( val.bv_len == 0 ) {
1894                                 return LDAP_SUCCESS;
1895                         }
1896                 }
1897
1898                 if( !OID_SEPARATOR( val.bv_val[0] )) {
1899                         break;
1900                 }
1901
1902                 val.bv_val++;
1903                 val.bv_len--;
1904         }
1905
1906         return LDAP_INVALID_SYNTAX;
1907 }
1908
1909 static int
1910 integerValidate(
1911         Syntax *syntax,
1912         struct berval *in )
1913 {
1914         ber_len_t i;
1915         struct berval val = *in;
1916
1917         if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
1918
1919         if ( val.bv_val[0] == '-' ) {
1920                 val.bv_len--;
1921                 val.bv_val++;
1922
1923                 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
1924                         return LDAP_INVALID_SYNTAX;
1925                 }
1926
1927                 if( val.bv_val[0] == '0' ) { /* "-0" */
1928                         return LDAP_INVALID_SYNTAX;
1929                 }
1930
1931         } else if ( val.bv_val[0] == '0' ) {
1932                 if( val.bv_len > 1 ) { /* "0<more>" */
1933                         return LDAP_INVALID_SYNTAX;
1934                 }
1935
1936                 return LDAP_SUCCESS;
1937         }
1938
1939         for( i=0; i < val.bv_len; i++ ) {
1940                 if( !ASCII_DIGIT(val.bv_val[i]) ) {
1941                         return LDAP_INVALID_SYNTAX;
1942                 }
1943         }
1944
1945         return LDAP_SUCCESS;
1946 }
1947
1948 static int
1949 integerMatch(
1950         int *matchp,
1951         slap_mask_t flags,
1952         Syntax *syntax,
1953         MatchingRule *mr,
1954         struct berval *value,
1955         void *assertedValue )
1956 {
1957         struct berval *asserted = (struct berval *) assertedValue;
1958         int vsign = 1, asign = 1;       /* default sign = '+' */
1959         struct berval v, a;
1960         int match;
1961
1962         v = *value;
1963         if( v.bv_val[0] == '-' ) {
1964                 vsign = -1;
1965                 v.bv_val++;
1966                 v.bv_len--;
1967         }
1968
1969         if( BER_BVISEMPTY( &v ) ) vsign = 0;
1970
1971         a = *asserted;
1972         if( a.bv_val[0] == '-' ) {
1973                 asign = -1;
1974                 a.bv_val++;
1975                 a.bv_len--;
1976         }
1977
1978         if( BER_BVISEMPTY( &a ) ) vsign = 0;
1979
1980         match = vsign - asign;
1981         if( match == 0 ) {
1982                 match = ( v.bv_len != a.bv_len
1983                         ? ( v.bv_len < a.bv_len ? -1 : 1 )
1984                         : memcmp( v.bv_val, a.bv_val, v.bv_len ));
1985                 if( vsign < 0 ) match = -match;
1986         }
1987
1988         *matchp = match;
1989         return LDAP_SUCCESS;
1990 }
1991         
1992 static int
1993 countryStringValidate(
1994         Syntax *syntax,
1995         struct berval *val )
1996 {
1997         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
1998
1999         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2000                 return LDAP_INVALID_SYNTAX;
2001         }
2002         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2003                 return LDAP_INVALID_SYNTAX;
2004         }
2005
2006         return LDAP_SUCCESS;
2007 }
2008
2009 static int
2010 printableStringValidate(
2011         Syntax *syntax,
2012         struct berval *val )
2013 {
2014         ber_len_t i;
2015
2016         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2017
2018         for(i=0; i < val->bv_len; i++) {
2019                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2020                         return LDAP_INVALID_SYNTAX;
2021                 }
2022         }
2023
2024         return LDAP_SUCCESS;
2025 }
2026
2027 static int
2028 printablesStringValidate(
2029         Syntax *syntax,
2030         struct berval *val )
2031 {
2032         ber_len_t i, len;
2033
2034         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2035
2036         for(i=0,len=0; i < val->bv_len; i++) {
2037                 int c = val->bv_val[i];
2038
2039                 if( c == '$' ) {
2040                         if( len == 0 ) {
2041                                 return LDAP_INVALID_SYNTAX;
2042                         }
2043                         len = 0;
2044
2045                 } else if ( SLAP_PRINTABLE(c) ) {
2046                         len++;
2047                 } else {
2048                         return LDAP_INVALID_SYNTAX;
2049                 }
2050         }
2051
2052         if( len == 0 ) {
2053                 return LDAP_INVALID_SYNTAX;
2054         }
2055
2056         return LDAP_SUCCESS;
2057 }
2058
2059 static int
2060 IA5StringValidate(
2061         Syntax *syntax,
2062         struct berval *val )
2063 {
2064         ber_len_t i;
2065
2066         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2067
2068         for(i=0; i < val->bv_len; i++) {
2069                 if( !LDAP_ASCII(val->bv_val[i]) ) {
2070                         return LDAP_INVALID_SYNTAX;
2071                 }
2072         }
2073
2074         return LDAP_SUCCESS;
2075 }
2076
2077 static int
2078 IA5StringNormalize(
2079         slap_mask_t use,
2080         Syntax *syntax,
2081         MatchingRule *mr,
2082         struct berval *val,
2083         struct berval *normalized,
2084         void *ctx )
2085 {
2086         char *p, *q;
2087         int casefold = !SLAP_MR_ASSOCIATED(mr, slap_schema.si_mr_caseExactIA5Match);
2088
2089         assert( !BER_BVISEMPTY( val ) );
2090
2091         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
2092
2093         p = val->bv_val;
2094
2095         /* Ignore initial whitespace */
2096         while ( ASCII_SPACE( *p ) ) p++;
2097
2098         normalized->bv_val = ber_strdup_x( p, ctx );
2099         p = q = normalized->bv_val;
2100
2101         while ( *p ) {
2102                 if ( ASCII_SPACE( *p ) ) {
2103                         *q++ = *p++;
2104
2105                         /* Ignore the extra whitespace */
2106                         while ( ASCII_SPACE( *p ) ) {
2107                                 p++;
2108                         }
2109
2110                 } else if ( casefold ) {
2111                         /* Most IA5 rules require casefolding */
2112                         *q++ = TOLOWER(*p); p++;
2113
2114                 } else {
2115                         *q++ = *p++;
2116                 }
2117         }
2118
2119         assert( normalized->bv_val <= p );
2120         assert( q <= p );
2121
2122         /*
2123          * If the string ended in space, backup the pointer one
2124          * position.  One is enough because the above loop collapsed
2125          * all whitespace to a single space.
2126          */
2127         if ( ASCII_SPACE( q[-1] ) ) --q;
2128
2129         /* null terminate */
2130         *q = '\0';
2131
2132         normalized->bv_len = q - normalized->bv_val;
2133         if( BER_BVISEMPTY( normalized ) ) {
2134                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2135                 normalized->bv_val[0] = ' ';
2136                 normalized->bv_val[1] = '\0';
2137                 normalized->bv_len = 1;
2138         }
2139
2140         return LDAP_SUCCESS;
2141 }
2142
2143 static int
2144 UUIDValidate(
2145         Syntax *syntax,
2146         struct berval *in )
2147 {
2148         int i;
2149         if( in->bv_len != 36 ) {
2150                 return LDAP_INVALID_SYNTAX;
2151         }
2152
2153         for( i=0; i<36; i++ ) {
2154                 switch(i) {
2155                         case 8:
2156                         case 13:
2157                         case 18:
2158                         case 23:
2159                                 if( in->bv_val[i] != '-' ) {
2160                                         return LDAP_INVALID_SYNTAX;
2161                                 }
2162                                 break;
2163                         default:
2164                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2165                                         return LDAP_INVALID_SYNTAX;
2166                                 }
2167                 }
2168         }
2169         
2170         return LDAP_SUCCESS;
2171 }
2172
2173 static int
2174 UUIDNormalize(
2175         slap_mask_t usage,
2176         Syntax *syntax,
2177         MatchingRule *mr,
2178         struct berval *val,
2179         struct berval *normalized,
2180         void *ctx )
2181 {
2182         unsigned char octet = '\0';
2183         int i;
2184         int j;
2185         normalized->bv_len = 16;
2186         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2187
2188         for( i=0, j=0; i<36; i++ ) {
2189                 unsigned char nibble;
2190                 if( val->bv_val[i] == '-' ) {
2191                         continue;
2192
2193                 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2194                         nibble = val->bv_val[i] - '0';
2195
2196                 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2197                         nibble = val->bv_val[i] - ('a'-10);
2198
2199                 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2200                         nibble = val->bv_val[i] - ('A'-10);
2201
2202                 } else {
2203                         slap_sl_free( normalized->bv_val, ctx );
2204                         return LDAP_INVALID_SYNTAX;
2205                 }
2206
2207                 if( j & 1 ) {
2208                         octet |= nibble;
2209                         normalized->bv_val[j>>1] = octet;
2210                 } else {
2211                         octet = nibble << 4;
2212                 }
2213                 j++;
2214         }
2215
2216         normalized->bv_val[normalized->bv_len] = 0;
2217         return LDAP_SUCCESS;
2218 }
2219
2220
2221
2222 static int
2223 numericStringValidate(
2224         Syntax *syntax,
2225         struct berval *in )
2226 {
2227         ber_len_t i;
2228
2229         if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2230
2231         for(i=0; i < in->bv_len; i++) {
2232                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2233                         return LDAP_INVALID_SYNTAX;
2234                 }
2235         }
2236
2237         return LDAP_SUCCESS;
2238 }
2239
2240 static int
2241 numericStringNormalize(
2242         slap_mask_t usage,
2243         Syntax *syntax,
2244         MatchingRule *mr,
2245         struct berval *val,
2246         struct berval *normalized,
2247         void *ctx )
2248 {
2249         /* removal all spaces */
2250         char *p, *q;
2251
2252         assert( !BER_BVISEMPTY( val ) );
2253
2254         normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2255
2256         p = val->bv_val;
2257         q = normalized->bv_val;
2258
2259         while ( *p ) {
2260                 if ( ASCII_SPACE( *p ) ) {
2261                         /* Ignore whitespace */
2262                         p++;
2263                 } else {
2264                         *q++ = *p++;
2265                 }
2266         }
2267
2268         /* we should have copied no more then is in val */
2269         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2270
2271         /* null terminate */
2272         *q = '\0';
2273
2274         normalized->bv_len = q - normalized->bv_val;
2275
2276         if( BER_BVISEMPTY( normalized ) ) {
2277                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2278                 normalized->bv_val[0] = ' ';
2279                 normalized->bv_val[1] = '\0';
2280                 normalized->bv_len = 1;
2281         }
2282
2283         return LDAP_SUCCESS;
2284 }
2285
2286 /*
2287  * Integer conversion macros that will use the largest available
2288  * type.
2289  */
2290 #if defined(HAVE_STRTOLL) && defined(LLONG_MAX) \
2291         && defined(LLONG_MIN) && defined(HAVE_LONG_LONG)
2292 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
2293 # define SLAP_LONG_MAX       LLONG_MAX
2294 # define SLAP_LONG_MIN       LLONG_MIN
2295 # define SLAP_LONG           long long
2296 #else
2297 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
2298 # define SLAP_LONG_MAX       LONG_MAX
2299 # define SLAP_LONG_MIN       LONG_MIN
2300 # define SLAP_LONG           long
2301 #endif /* HAVE_STRTOLL ... */
2302
2303 static int
2304 integerBitAndMatch(
2305         int *matchp,
2306         slap_mask_t flags,
2307         Syntax *syntax,
2308         MatchingRule *mr,
2309         struct berval *value,
2310         void *assertedValue )
2311 {
2312         SLAP_LONG lValue, lAssertedValue;
2313
2314         /* safe to assume integers are NUL terminated? */
2315         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2316         if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX) &&
2317                 errno == ERANGE )
2318         {
2319                 return LDAP_CONSTRAINT_VIOLATION;
2320         }
2321
2322         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2323                 NULL, 10);
2324         if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX ) &&
2325                 errno == ERANGE )
2326         {
2327                 return LDAP_CONSTRAINT_VIOLATION;
2328         }
2329
2330         *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2331         return LDAP_SUCCESS;
2332 }
2333
2334 static int
2335 integerBitOrMatch(
2336         int *matchp,
2337         slap_mask_t flags,
2338         Syntax *syntax,
2339         MatchingRule *mr,
2340         struct berval *value,
2341         void *assertedValue )
2342 {
2343         SLAP_LONG lValue, lAssertedValue;
2344
2345         /* safe to assume integers are NUL terminated? */
2346         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2347         if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX ) &&
2348                 errno == ERANGE )
2349         {
2350                 return LDAP_CONSTRAINT_VIOLATION;
2351         }
2352
2353         lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2354                 NULL, 10);
2355         if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX ) &&
2356                 errno == ERANGE )
2357         {
2358                 return LDAP_CONSTRAINT_VIOLATION;
2359         }
2360
2361         *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2362         return LDAP_SUCCESS;
2363 }
2364
2365 static int
2366 serialNumberAndIssuerValidate(
2367         Syntax *syntax,
2368         struct berval *in )
2369 {
2370         int rc;
2371         ber_len_t n;
2372         struct berval sn, i;
2373         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2374
2375         i.bv_val = strchr( in->bv_val, '$' );
2376         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2377
2378         sn.bv_val = in->bv_val;
2379         sn.bv_len = i.bv_val - in->bv_val;
2380
2381         i.bv_val++;
2382         i.bv_len = in->bv_len - (sn.bv_len + 1);
2383
2384         /* validate serial number (strict for now) */
2385         for( n=0; n < sn.bv_len; n++ ) {
2386                 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2387         }
2388
2389         /* validate DN */
2390         rc = dnValidate( NULL, &i );
2391         if( rc ) return LDAP_INVALID_SYNTAX;
2392
2393         return LDAP_SUCCESS;
2394 }
2395
2396 int
2397 serialNumberAndIssuerPretty(
2398         Syntax *syntax,
2399         struct berval *val,
2400         struct berval *out,
2401         void *ctx )
2402 {
2403         int rc;
2404         ber_len_t n;
2405         struct berval sn, i, newi;
2406
2407         assert( val != NULL );
2408         assert( out != NULL );
2409
2410         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
2411                 val->bv_val, 0, 0 );
2412
2413         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2414
2415         i.bv_val = strchr( val->bv_val, '$' );
2416         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2417
2418         sn.bv_val = val->bv_val;
2419         sn.bv_len = i.bv_val - val->bv_val;
2420
2421         i.bv_val++;
2422         i.bv_len = val->bv_len - (sn.bv_len + 1);
2423
2424         /* eat leading zeros */
2425         for( n=0; n < (sn.bv_len-1); n++ ) {
2426                 if( sn.bv_val[n] != '0' ) break;
2427         }
2428         sn.bv_val += n;
2429         sn.bv_len -= n;
2430
2431         for( n=0; n < sn.bv_len; n++ ) {
2432                 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2433         }
2434
2435         /* pretty DN */
2436         rc = dnPretty( syntax, &i, &newi, ctx );
2437         if( rc ) return LDAP_INVALID_SYNTAX;
2438
2439         /* make room from sn + "$" */
2440         out->bv_len = sn.bv_len + newi.bv_len + 1;
2441         out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2442
2443         if( out->bv_val == NULL ) {
2444                 out->bv_len = 0;
2445                 slap_sl_free( newi.bv_val, ctx );
2446                 return LDAP_OTHER;
2447         }
2448
2449         /* push issuer over */
2450         AC_MEMCPY( &out->bv_val[sn.bv_len+1], out->bv_val, newi.bv_len );
2451         /* insert sn and "$" */
2452         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2453         out->bv_val[sn.bv_len] = '$';
2454         /* terminate */
2455         out->bv_val[out->bv_len] = '\0';
2456
2457         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
2458                 out->bv_val, 0, 0 );
2459
2460         return LDAP_SUCCESS;
2461 }
2462
2463 /*
2464  * This routine is called by certificateExactNormalize when
2465  * certificateExactNormalize receives a search string instead of
2466  * a certificate. This routine checks if the search value is valid
2467  * and then returns the normalized value
2468  */
2469 static int
2470 serialNumberAndIssuerNormalize(
2471         slap_mask_t usage,
2472         Syntax *syntax,
2473         MatchingRule *mr,
2474         struct berval *val,
2475         struct berval *out,
2476         void *ctx )
2477 {
2478         int rc;
2479         ber_len_t n;
2480         struct berval sn, i, newi;
2481
2482         assert( val != NULL );
2483         assert( out != NULL );
2484
2485         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
2486                 val->bv_val, 0, 0 );
2487
2488         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2489
2490         i.bv_val = strchr( val->bv_val, '$' );
2491         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2492
2493         sn.bv_val = val->bv_val;
2494         sn.bv_len = i.bv_val - val->bv_val;
2495
2496         i.bv_val++;
2497         i.bv_len = val->bv_len - (sn.bv_len + 1);
2498
2499         /* eat leading zeros */
2500         for( n=0; n < (sn.bv_len-1); n++ ) {
2501                 if( sn.bv_val[n] != '0' ) break;
2502         }
2503         sn.bv_val += n;
2504         sn.bv_len -= n;
2505
2506         for( n=0; n < sn.bv_len; n++ ) {
2507                 if( !ASCII_DIGIT(sn.bv_val[n]) ) {
2508                         return LDAP_INVALID_SYNTAX;
2509                 }
2510         }
2511
2512         /* pretty DN */
2513         rc = dnNormalize( usage, syntax, mr, &i, &newi, ctx );
2514         if( rc ) return LDAP_INVALID_SYNTAX;
2515
2516         /* make room from sn + "$" */
2517         out->bv_len = sn.bv_len + newi.bv_len + 1;
2518         out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2519
2520         if( out->bv_val == NULL ) {
2521                 out->bv_len = 0;
2522                 slap_sl_free( newi.bv_val, ctx );
2523                 return LDAP_OTHER;
2524         }
2525
2526         /* push issuer over */
2527         AC_MEMCPY( &out->bv_val[sn.bv_len+1], out->bv_val, newi.bv_len );
2528         /* insert sn and "$" */
2529         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2530         out->bv_val[sn.bv_len] = '$';
2531         /* terminate */
2532         out->bv_val[out->bv_len] = '\0';
2533
2534         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
2535                 out->bv_val, 0, 0 );
2536
2537         return rc;
2538 }
2539
2540 #ifdef HAVE_TLS
2541 static int
2542 certificateExactNormalize(
2543         slap_mask_t usage,
2544         Syntax *syntax,
2545         MatchingRule *mr,
2546         struct berval *val,
2547         struct berval *normalized,
2548         void *ctx )
2549 {
2550         int rc = LDAP_INVALID_SYNTAX;
2551         unsigned char *p;
2552         char *serial = NULL;
2553         ber_len_t seriallen;
2554         struct berval issuer_dn = BER_BVNULL;
2555         X509_NAME *name = NULL;
2556         ASN1_INTEGER *sn = NULL;
2557         X509 *xcert = NULL;
2558
2559         if( BER_BVISEMPTY( val ) ) goto done;
2560
2561         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
2562                 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
2563         }
2564
2565         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) );
2566
2567         p = (unsigned char *)val->bv_val;
2568         xcert = d2i_X509( NULL, &p, val->bv_len);
2569         if( xcert == NULL ) goto done;
2570
2571         sn=X509_get_serialNumber(xcert);
2572         if ( sn == NULL ) goto done;
2573         serial=i2s_ASN1_INTEGER(0, sn );
2574         if( serial == NULL ) goto done;
2575         seriallen=strlen(serial);
2576
2577         name=X509_get_issuer_name(xcert);
2578         if( name == NULL ) goto done;
2579         rc = dnX509normalize( name, &issuer_dn );
2580         if( rc != LDAP_SUCCESS ) goto done;
2581
2582         normalized->bv_len = seriallen + issuer_dn.bv_len + 1;
2583         normalized->bv_val = ch_malloc(normalized->bv_len+1);
2584         p = (unsigned char *)normalized->bv_val;
2585         AC_MEMCPY(p, serial, seriallen);
2586         p += seriallen;
2587         *p++ = '$';
2588         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
2589         p += issuer_dn.bv_len;
2590         *p = '\0';
2591
2592         Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
2593                 normalized->bv_val, NULL, NULL );
2594
2595 done:
2596         if (xcert) X509_free(xcert);
2597         if (serial) ch_free(serial);
2598         if (issuer_dn.bv_val) ber_memfree(issuer_dn.bv_val);
2599
2600         return rc;
2601 }
2602 #endif /* HAVE_TLS */
2603
2604
2605 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
2606 /* slight optimization - does not need the start parameter */
2607 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
2608 enum { start = 0 };
2609 #endif
2610
2611 static int
2612 check_time_syntax (struct berval *val,
2613         int start,
2614         int *parts,
2615         struct berval *fraction)
2616 {
2617         /*
2618          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
2619          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
2620          * GeneralizedTime supports leap seconds, UTCTime does not.
2621          */
2622         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
2623         static const int mdays[2][12] = {
2624                 /* non-leap years */
2625                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
2626                 /* leap years */
2627                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
2628         };
2629         char *p, *e;
2630         int part, c, c1, c2, tzoffset, leapyear = 0;
2631
2632         p = val->bv_val;
2633         e = p + val->bv_len;
2634
2635 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2636         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
2637 #endif
2638         for (part = start; part < 7 && p < e; part++) {
2639                 c1 = *p;
2640                 if (!ASCII_DIGIT(c1)) {
2641                         break;
2642                 }
2643                 p++;
2644                 if (p == e) {
2645                         return LDAP_INVALID_SYNTAX;
2646                 }
2647                 c = *p++;
2648                 if (!ASCII_DIGIT(c)) {
2649                         return LDAP_INVALID_SYNTAX;
2650                 }
2651                 c += c1 * 10 - '0' * 11;
2652                 if ((part | 1) == 3) {
2653                         --c;
2654                         if (c < 0) {
2655                                 return LDAP_INVALID_SYNTAX;
2656                         }
2657                 }
2658                 if (c >= ceiling[part]) {
2659                         if (! (c == 60 && part == 6 && start == 0))
2660                                 return LDAP_INVALID_SYNTAX;
2661                 }
2662                 parts[part] = c;
2663         }
2664         if (part < 5 + start) {
2665                 return LDAP_INVALID_SYNTAX;
2666         }
2667         for (; part < 9; part++) {
2668                 parts[part] = 0;
2669         }
2670
2671         /* leapyear check for the Gregorian calendar (year>1581) */
2672         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
2673                 leapyear = 1;
2674         }
2675
2676         if (parts[3] >= mdays[leapyear][parts[2]]) {
2677                 return LDAP_INVALID_SYNTAX;
2678         }
2679
2680         if (start == 0) {
2681                 fraction->bv_val = p;
2682                 fraction->bv_len = 0;
2683                 if (p < e && (*p == '.' || *p == ',')) {
2684                         char *end_num;
2685                         while (++p < e && ASCII_DIGIT(*p)) {
2686                                 /* EMTPY */;
2687                         }
2688                         if (p - fraction->bv_val == 1) {
2689                                 return LDAP_INVALID_SYNTAX;
2690                         }
2691                         for (end_num = p; end_num[-1] == '0'; --end_num) {
2692                                 /* EMPTY */;
2693                         }
2694                         c = end_num - fraction->bv_val;
2695                         if (c != 1) fraction->bv_len = c;
2696                 }
2697         }
2698
2699         if (p == e) {
2700                 /* no time zone */
2701                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2702         }
2703
2704         tzoffset = *p++;
2705         switch (tzoffset) {
2706         default:
2707                 return LDAP_INVALID_SYNTAX;
2708         case 'Z':
2709                 /* UTC */
2710                 break;
2711         case '+':
2712         case '-':
2713                 for (part = 7; part < 9 && p < e; part++) {
2714                         c1 = *p;
2715                         if (!ASCII_DIGIT(c1)) {
2716                                 break;
2717                         }
2718                         p++;
2719                         if (p == e) {
2720                                 return LDAP_INVALID_SYNTAX;
2721                         }
2722                         c2 = *p++;
2723                         if (!ASCII_DIGIT(c2)) {
2724                                 return LDAP_INVALID_SYNTAX;
2725                         }
2726                         parts[part] = c1 * 10 + c2 - '0' * 11;
2727                         if (parts[part] >= ceiling[part]) {
2728                                 return LDAP_INVALID_SYNTAX;
2729                         }
2730                 }
2731                 if (part < 8 + start) {
2732                         return LDAP_INVALID_SYNTAX;
2733                 }
2734
2735                 if (tzoffset == '-') {
2736                         /* negative offset to UTC, ie west of Greenwich */
2737                         parts[4] += parts[7];
2738                         parts[5] += parts[8];
2739                         /* offset is just hhmm, no seconds */
2740                         for (part = 6; --part >= 0; ) {
2741                                 if (part != 3) {
2742                                         c = ceiling[part];
2743                                 } else {
2744                                         c = mdays[leapyear][parts[2]];
2745                                 }
2746                                 if (parts[part] >= c) {
2747                                         if (part == 0) {
2748                                                 return LDAP_INVALID_SYNTAX;
2749                                         }
2750                                         parts[part] -= c;
2751                                         parts[part - 1]++;
2752                                         continue;
2753                                 } else if (part != 5) {
2754                                         break;
2755                                 }
2756                         }
2757                 } else {
2758                         /* positive offset to UTC, ie east of Greenwich */
2759                         parts[4] -= parts[7];
2760                         parts[5] -= parts[8];
2761                         for (part = 6; --part >= 0; ) {
2762                                 if (parts[part] < 0) {
2763                                         if (part == 0) {
2764                                                 return LDAP_INVALID_SYNTAX;
2765                                         }
2766                                         if (part != 3) {
2767                                                 c = ceiling[part];
2768                                         } else {
2769                                                 /* make first arg to % non-negative */
2770                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
2771                                         }
2772                                         parts[part] += c;
2773                                         parts[part - 1]--;
2774                                         continue;
2775                                 } else if (part != 5) {
2776                                         break;
2777                                 }
2778                         }
2779                 }
2780         }
2781
2782         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2783 }
2784
2785 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2786
2787 #if 0
2788 static int
2789 xutcTimeNormalize(
2790         Syntax *syntax,
2791         struct berval *val,
2792         struct berval *normalized )
2793 {
2794         int parts[9], rc;
2795
2796         rc = check_time_syntax(val, 1, parts, NULL);
2797         if (rc != LDAP_SUCCESS) {
2798                 return rc;
2799         }
2800
2801         normalized->bv_val = ch_malloc( 14 );
2802         if ( normalized->bv_val == NULL ) {
2803                 return LBER_ERROR_MEMORY;
2804         }
2805
2806         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
2807                 parts[1], parts[2] + 1, parts[3] + 1,
2808                 parts[4], parts[5], parts[6] );
2809         normalized->bv_len = 13;
2810
2811         return LDAP_SUCCESS;
2812 }
2813 #endif /* 0 */
2814
2815 static int
2816 utcTimeValidate(
2817         Syntax *syntax,
2818         struct berval *in )
2819 {
2820         int parts[9];
2821         return check_time_syntax(in, 1, parts, NULL);
2822 }
2823
2824 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
2825
2826 static int
2827 generalizedTimeValidate(
2828         Syntax *syntax,
2829         struct berval *in )
2830 {
2831         int parts[9];
2832         struct berval fraction;
2833         return check_time_syntax(in, 0, parts, &fraction);
2834 }
2835
2836 static int
2837 generalizedTimeNormalize(
2838         slap_mask_t usage,
2839         Syntax *syntax,
2840         MatchingRule *mr,
2841         struct berval *val,
2842         struct berval *normalized,
2843         void *ctx )
2844 {
2845         int parts[9], rc;
2846         unsigned int len;
2847         struct berval fraction;
2848
2849         rc = check_time_syntax(val, 0, parts, &fraction);
2850         if (rc != LDAP_SUCCESS) {
2851                 return rc;
2852         }
2853
2854         len = sizeof("YYYYmmddHHMMSSZ")-1 + fraction.bv_len;
2855         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
2856         if ( BER_BVISNULL( normalized ) ) {
2857                 return LBER_ERROR_MEMORY;
2858         }
2859
2860         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
2861                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
2862                 parts[4], parts[5], parts[6] );
2863         if ( !BER_BVISEMPTY( &fraction ) ) {
2864                 memcpy( normalized->bv_val + sizeof("YYYYmmddHHMMSSZ")-2,
2865                         fraction.bv_val, fraction.bv_len );
2866                 normalized->bv_val[sizeof("YYYYmmddHHMMSSZ")-2] = '.';
2867         }
2868         strcpy( normalized->bv_val + len-1, "Z" );
2869         normalized->bv_len = len;
2870
2871         return LDAP_SUCCESS;
2872 }
2873
2874 static int
2875 generalizedTimeOrderingMatch(
2876         int *matchp,
2877         slap_mask_t flags,
2878         Syntax *syntax,
2879         MatchingRule *mr,
2880         struct berval *value,
2881         void *assertedValue )
2882 {
2883         struct berval *asserted = (struct berval *) assertedValue;
2884         ber_len_t v_len  = value->bv_len;
2885         ber_len_t av_len = asserted->bv_len;
2886
2887         /* ignore trailing 'Z' when comparing */
2888         int match = memcmp( value->bv_val, asserted->bv_val,
2889                 (v_len < av_len ? v_len : av_len) - 1 );
2890         if ( match == 0 ) match = v_len - av_len;
2891
2892         *matchp = match;
2893         return LDAP_SUCCESS;
2894 }
2895
2896 /* Index generation function */
2897 int generalizedTimeIndexer(
2898         slap_mask_t use,
2899         slap_mask_t flags,
2900         Syntax *syntax,
2901         MatchingRule *mr,
2902         struct berval *prefix,
2903         BerVarray values,
2904         BerVarray *keysp,
2905         void *ctx )
2906 {
2907         int i, j;
2908         BerVarray keys;
2909         char tmp[5];
2910         BerValue bvtmp; /* 40 bit index */
2911         struct lutil_tm tm;
2912         struct lutil_timet tt;
2913
2914         bvtmp.bv_len = sizeof(tmp);
2915         bvtmp.bv_val = tmp;
2916         for( i=0; values[i].bv_val != NULL; i++ ) {
2917                 /* just count them */
2918         }
2919
2920         /* we should have at least one value at this point */
2921         assert( i > 0 );
2922
2923         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2924
2925         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
2926         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
2927                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
2928                 /* Use 40 bits of time for key */
2929                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
2930                         lutil_tm2time( &tm, &tt );
2931                         tmp[0] = tt.tt_gsec & 0xff;
2932                         tmp[4] = tt.tt_sec & 0xff;
2933                         tt.tt_sec >>= 8;
2934                         tmp[3] = tt.tt_sec & 0xff;
2935                         tt.tt_sec >>= 8;
2936                         tmp[2] = tt.tt_sec & 0xff;
2937                         tt.tt_sec >>= 8;
2938                         tmp[1] = tt.tt_sec & 0xff;
2939                         
2940                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
2941                 }
2942         }
2943
2944         keys[j].bv_val = NULL;
2945         keys[j].bv_len = 0;
2946
2947         *keysp = keys;
2948
2949         return LDAP_SUCCESS;
2950 }
2951
2952 /* Index generation function */
2953 int generalizedTimeFilter(
2954         slap_mask_t use,
2955         slap_mask_t flags,
2956         Syntax *syntax,
2957         MatchingRule *mr,
2958         struct berval *prefix,
2959         void * assertedValue,
2960         BerVarray *keysp,
2961         void *ctx )
2962 {
2963         BerVarray keys;
2964         char tmp[5];
2965         BerValue bvtmp; /* 40 bit index */
2966         BerValue *value = (BerValue *) assertedValue;
2967         struct lutil_tm tm;
2968         struct lutil_timet tt;
2969         
2970         bvtmp.bv_len = sizeof(tmp);
2971         bvtmp.bv_val = tmp;
2972         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
2973         /* Use 40 bits of time for key */
2974         if ( value->bv_val && value->bv_len >= 10 &&
2975                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
2976
2977                 lutil_tm2time( &tm, &tt );
2978                 tmp[0] = tt.tt_gsec & 0xff;
2979                 tmp[4] = tt.tt_sec & 0xff;
2980                 tt.tt_sec >>= 8;
2981                 tmp[3] = tt.tt_sec & 0xff;
2982                 tt.tt_sec >>= 8;
2983                 tmp[2] = tt.tt_sec & 0xff;
2984                 tt.tt_sec >>= 8;
2985                 tmp[1] = tt.tt_sec & 0xff;
2986
2987                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2988                 ber_dupbv_x(keys, &bvtmp, ctx );
2989                 keys[1].bv_val = NULL;
2990                 keys[1].bv_len = 0;
2991         } else {
2992                 keys = NULL;
2993         }
2994
2995         *keysp = keys;
2996
2997         return LDAP_SUCCESS;
2998 }
2999
3000 static int
3001 deliveryMethodValidate(
3002         Syntax *syntax,
3003         struct berval *val )
3004 {
3005 #undef LENOF
3006 #define LENOF(s) (sizeof(s)-1)
3007         struct berval tmp = *val;
3008         /*
3009      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
3010          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
3011          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
3012          */
3013 again:
3014         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3015
3016         switch( tmp.bv_val[0] ) {
3017         case 'a':
3018         case 'A':
3019                 if(( tmp.bv_len >= LENOF("any") ) &&
3020                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
3021                 {
3022                         tmp.bv_len -= LENOF("any");
3023                         tmp.bv_val += LENOF("any");
3024                         break;
3025                 }
3026                 return LDAP_INVALID_SYNTAX;
3027
3028         case 'm':
3029         case 'M':
3030                 if(( tmp.bv_len >= LENOF("mhs") ) &&
3031                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
3032                 {
3033                         tmp.bv_len -= LENOF("mhs");
3034                         tmp.bv_val += LENOF("mhs");
3035                         break;
3036                 }
3037                 return LDAP_INVALID_SYNTAX;
3038
3039         case 'p':
3040         case 'P':
3041                 if(( tmp.bv_len >= LENOF("physical") ) &&
3042                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
3043                 {
3044                         tmp.bv_len -= LENOF("physical");
3045                         tmp.bv_val += LENOF("physical");
3046                         break;
3047                 }
3048                 return LDAP_INVALID_SYNTAX;
3049
3050         case 't':
3051         case 'T': /* telex or teletex or telephone */
3052                 if(( tmp.bv_len >= LENOF("telex") ) &&
3053                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
3054                 {
3055                         tmp.bv_len -= LENOF("telex");
3056                         tmp.bv_val += LENOF("telex");
3057                         break;
3058                 }
3059                 if(( tmp.bv_len >= LENOF("teletex") ) &&
3060                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
3061                 {
3062                         tmp.bv_len -= LENOF("teletex");
3063                         tmp.bv_val += LENOF("teletex");
3064                         break;
3065                 }
3066                 if(( tmp.bv_len >= LENOF("telephone") ) &&
3067                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
3068                 {
3069                         tmp.bv_len -= LENOF("telephone");
3070                         tmp.bv_val += LENOF("telephone");
3071                         break;
3072                 }
3073                 return LDAP_INVALID_SYNTAX;
3074
3075         case 'g':
3076         case 'G': /* g3fax or g4fax */
3077                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
3078                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
3079                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
3080                 {
3081                         tmp.bv_len -= LENOF("g3fax");
3082                         tmp.bv_val += LENOF("g3fax");
3083                         break;
3084                 }
3085                 return LDAP_INVALID_SYNTAX;
3086
3087         case 'i':
3088         case 'I':
3089                 if(( tmp.bv_len >= LENOF("ia5") ) &&
3090                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
3091                 {
3092                         tmp.bv_len -= LENOF("ia5");
3093                         tmp.bv_val += LENOF("ia5");
3094                         break;
3095                 }
3096                 return LDAP_INVALID_SYNTAX;
3097
3098         case 'v':
3099         case 'V':
3100                 if(( tmp.bv_len >= LENOF("videotex") ) &&
3101                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
3102                 {
3103                         tmp.bv_len -= LENOF("videotex");
3104                         tmp.bv_val += LENOF("videotex");
3105                         break;
3106                 }
3107                 return LDAP_INVALID_SYNTAX;
3108
3109         default:
3110                 return LDAP_INVALID_SYNTAX;
3111         }
3112
3113         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
3114
3115         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3116                 tmp.bv_len++;
3117                 tmp.bv_val--;
3118         }
3119         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
3120                 tmp.bv_len++;
3121                 tmp.bv_val--;
3122         } else {
3123                 return LDAP_INVALID_SYNTAX;
3124         }
3125         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3126                 tmp.bv_len++;
3127                 tmp.bv_val--;
3128         }
3129
3130         goto again;
3131 }
3132
3133 static int
3134 nisNetgroupTripleValidate(
3135         Syntax *syntax,
3136         struct berval *val )
3137 {
3138         char *p, *e;
3139         int commas = 0;
3140
3141         if ( BER_BVISEMPTY( val ) ) {
3142                 return LDAP_INVALID_SYNTAX;
3143         }
3144
3145         p = (char *)val->bv_val;
3146         e = p + val->bv_len;
3147
3148         if ( *p != '(' /*')'*/ ) {
3149                 return LDAP_INVALID_SYNTAX;
3150         }
3151
3152         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
3153                 if ( *p == ',' ) {
3154                         commas++;
3155                         if ( commas > 2 ) {
3156                                 return LDAP_INVALID_SYNTAX;
3157                         }
3158
3159                 } else if ( !AD_CHAR( *p ) ) {
3160                         return LDAP_INVALID_SYNTAX;
3161                 }
3162         }
3163
3164         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
3165                 return LDAP_INVALID_SYNTAX;
3166         }
3167
3168         p++;
3169
3170         if (p != e) {
3171                 return LDAP_INVALID_SYNTAX;
3172         }
3173
3174         return LDAP_SUCCESS;
3175 }
3176
3177 static int
3178 bootParameterValidate(
3179         Syntax *syntax,
3180         struct berval *val )
3181 {
3182         char *p, *e;
3183
3184         if ( BER_BVISEMPTY( val ) ) {
3185                 return LDAP_INVALID_SYNTAX;
3186         }
3187
3188         p = (char *)val->bv_val;
3189         e = p + val->bv_len;
3190
3191         /* key */
3192         for (; ( p < e ) && ( *p != '=' ); p++ ) {
3193                 if ( !AD_CHAR( *p ) ) {
3194                         return LDAP_INVALID_SYNTAX;
3195                 }
3196         }
3197
3198         if ( *p != '=' ) {
3199                 return LDAP_INVALID_SYNTAX;
3200         }
3201
3202         /* server */
3203         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
3204                 if ( !AD_CHAR( *p ) ) {
3205                         return LDAP_INVALID_SYNTAX;
3206                 }
3207         }
3208
3209         if ( *p != ':' ) {
3210                 return LDAP_INVALID_SYNTAX;
3211         }
3212
3213         /* path */
3214         for ( p++; p < e; p++ ) {
3215                 if ( !SLAP_PRINTABLE( *p ) ) {
3216                         return LDAP_INVALID_SYNTAX;
3217                 }
3218         }
3219
3220         return LDAP_SUCCESS;
3221 }
3222
3223 static int
3224 firstComponentNormalize(
3225         slap_mask_t usage,
3226         Syntax *syntax,
3227         MatchingRule *mr,
3228         struct berval *val,
3229         struct berval *normalized,
3230         void *ctx )
3231 {
3232         int rc;
3233         struct berval comp;
3234         ber_len_t len;
3235
3236         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
3237                 ber_dupbv_x( normalized, val, ctx );
3238                 return LDAP_SUCCESS;
3239         }
3240
3241         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3242
3243         if( val->bv_val[0] != '(' /*')'*/ &&
3244                 val->bv_val[0] != '{' /*'}'*/ )
3245         {
3246                 return LDAP_INVALID_SYNTAX;
3247         }
3248
3249         /* trim leading white space */
3250         for( len=1;
3251                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
3252                 len++ )
3253         {
3254                 /* empty */
3255         }
3256
3257         /* grab next word */
3258         comp.bv_val = &val->bv_val[len];
3259         len = val->bv_len - len;
3260         for( comp.bv_len = 0;
3261                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
3262                 comp.bv_len++ )
3263         {
3264                 /* empty */
3265         }
3266
3267         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
3268                 rc = numericoidValidate( NULL, &comp );
3269         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
3270                 rc = integerValidate( NULL, &comp );
3271         } else {
3272                 rc = LDAP_INVALID_SYNTAX;
3273         }
3274         
3275
3276         if( rc == LDAP_SUCCESS ) {
3277                 ber_dupbv_x( normalized, &comp, ctx );
3278         }
3279
3280         return rc;
3281 }
3282
3283
3284 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
3285 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
3286
3287 static slap_syntax_defs_rec syntax_defs[] = {
3288         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
3289                 X_BINARY X_NOT_H_R ")",
3290                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL},
3291         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
3292                 0, NULL, NULL},
3293         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
3294                 0, NULL, NULL},
3295         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
3296                 X_NOT_H_R ")",
3297                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3298         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
3299                 X_NOT_H_R ")",
3300                 SLAP_SYNTAX_BER, berValidate, NULL},
3301         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
3302                 0, bitStringValidate, NULL },
3303         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
3304                 0, booleanValidate, NULL},
3305         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
3306                 X_BINARY X_NOT_H_R ")",
3307                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, certificateValidate, NULL},
3308         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
3309                 X_BINARY X_NOT_H_R ")",
3310                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3311         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
3312                 X_BINARY X_NOT_H_R ")",
3313                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3314         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
3315                 0, countryStringValidate, NULL},
3316         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
3317                 0, dnValidate, dnPretty},
3318         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
3319                 0, rdnValidate, rdnPretty},
3320 #ifdef LDAP_COMP_MATCH
3321         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
3322                 0, allComponentsValidate, NULL},
3323         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
3324                 0, componentFilterValidate, NULL},
3325 #endif
3326         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
3327                 0, NULL, NULL},
3328         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
3329                 0, deliveryMethodValidate, NULL},
3330         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
3331                 0, UTF8StringValidate, NULL},
3332         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
3333                 0, NULL, NULL},
3334         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
3335                 0, NULL, NULL},
3336         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
3337                 0, NULL, NULL},
3338         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
3339                 0, NULL, NULL},
3340         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
3341                 0, NULL, NULL},
3342         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
3343                 0, printablesStringValidate, NULL},
3344         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
3345                 SLAP_SYNTAX_BLOB, NULL, NULL},
3346         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
3347                 0, generalizedTimeValidate, NULL},
3348         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
3349                 0, NULL, NULL},
3350         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
3351                 0, IA5StringValidate, NULL},
3352         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
3353                 0, integerValidate, NULL},
3354         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
3355                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3356         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
3357                 0, NULL, NULL},
3358         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
3359                 0, NULL, NULL},
3360         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
3361                 0, NULL, NULL},
3362         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
3363                 0, NULL, NULL},
3364         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
3365                 0, NULL, NULL},
3366         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
3367                 0, nameUIDValidate, nameUIDPretty },
3368         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
3369                 0, NULL, NULL},
3370         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
3371                 0, numericStringValidate, NULL},
3372         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
3373                 0, NULL, NULL},
3374         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
3375                 0, numericoidValidate, NULL},
3376         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
3377                 0, IA5StringValidate, NULL},
3378         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
3379                 0, blobValidate, NULL},
3380         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
3381                 0, UTF8StringValidate, NULL},
3382         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
3383                 0, NULL, NULL},
3384         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
3385                 0, NULL, NULL},
3386         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
3387                 0, printableStringValidate, NULL},
3388         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
3389 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
3390                 0, subtreeSpecificationValidate, NULL},
3391         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
3392                 X_BINARY X_NOT_H_R ")",
3393                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
3394         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
3395                 0, printableStringValidate, NULL},
3396         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
3397                 0, NULL, NULL},
3398         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
3399                 0, printablesStringValidate, NULL},
3400 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3401         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
3402                 0, utcTimeValidate, NULL},
3403 #endif
3404         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
3405                 0, NULL, NULL},
3406         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
3407                 0, NULL, NULL},
3408         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
3409                 0, NULL, NULL},
3410         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
3411                 0, NULL, NULL},
3412         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
3413                 0, NULL, NULL},
3414
3415         /* RFC 2307 NIS Syntaxes */
3416         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
3417                 0, nisNetgroupTripleValidate, NULL},
3418         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
3419                 0, bootParameterValidate, NULL},
3420
3421         /* From PKIX *//* This OID is not published yet. */
3422         {"( 1.2.826.0.1.3344810.7.1 DESC 'Certificate Serial Number and Issuer' )",
3423                 SLAP_SYNTAX_HIDE,
3424                 serialNumberAndIssuerValidate,
3425                 serialNumberAndIssuerPretty},
3426
3427 #ifdef SLAPD_AUTHPASSWD
3428         /* needs updating */
3429         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
3430                 SLAP_SYNTAX_HIDE, NULL, NULL},
3431 #endif
3432
3433         {"( 1.3.6.1.4.1.4203.666.2.6 DESC 'UUID' )",
3434                 SLAP_SYNTAX_HIDE, UUIDValidate, NULL},
3435
3436         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
3437                 SLAP_SYNTAX_HIDE, csnValidate, NULL},
3438
3439         /* OpenLDAP Void Syntax */
3440         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
3441                 SLAP_SYNTAX_HIDE, inValidate, NULL},
3442
3443 #ifdef SLAP_AUTHZ_SYNTAX
3444         /* FIXME: OID is unused, but not registered yet */
3445         {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
3446                 SLAP_SYNTAX_HIDE, authzValidate, authzPretty},
3447 #endif /* SLAP_AUTHZ_SYNTAX */
3448
3449         {NULL, 0, NULL, NULL}
3450 };
3451
3452 char *certificateExactMatchSyntaxes[] = {
3453         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
3454         NULL
3455 };
3456 #ifdef LDAP_COMP_MATCH
3457 char *componentFilterMatchSyntaxes[] = {
3458         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
3459         NULL
3460 };
3461 #endif
3462 char *directoryStringSyntaxes[] = {
3463         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
3464         NULL
3465 };
3466 char *integerFirstComponentMatchSyntaxes[] = {
3467         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
3468         "1.3.6.1.4.1.1466.115.121.1.17" /* ditStructureRuleDescription */,
3469         NULL
3470 };
3471 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
3472         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
3473         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
3474         "1.3.6.1.4.1.1466.115.121.1.16" /* ditContentRuleDescription */,
3475         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
3476         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
3477         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
3478         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
3479         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
3480         NULL
3481 };
3482
3483 /*
3484  * Other matching rules in X.520 that we do not use (yet):
3485  *
3486  * 2.5.13.25    uTCTimeMatch
3487  * 2.5.13.26    uTCTimeOrderingMatch
3488  * 2.5.13.31*   directoryStringFirstComponentMatch
3489  * 2.5.13.32*   wordMatch
3490  * 2.5.13.33*   keywordMatch
3491  * 2.5.13.36    certificatePairExactMatch
3492  * 2.5.13.37    certificatePairMatch
3493  * 2.5.13.38    certificateListExactMatch
3494  * 2.5.13.39    certificateListMatch
3495  * 2.5.13.40    algorithmIdentifierMatch
3496  * 2.5.13.41*   storedPrefixMatch
3497  * 2.5.13.42    attributeCertificateMatch
3498  * 2.5.13.43    readerAndKeyIDMatch
3499  * 2.5.13.44    attributeIntegrityMatch
3500  *
3501  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
3502  */
3503 static slap_mrule_defs_rec mrule_defs[] = {
3504         /*
3505          * EQUALITY matching rules must be listed after associated APPROX
3506          * matching rules.  So, we list all APPROX matching rules first.
3507          */
3508         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
3509                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3510                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3511                 NULL, NULL, directoryStringApproxMatch,
3512                 directoryStringApproxIndexer, directoryStringApproxFilter,
3513                 NULL},
3514
3515         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
3516                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3517                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3518                 NULL, NULL, IA5StringApproxMatch,
3519                 IA5StringApproxIndexer, IA5StringApproxFilter,
3520                 NULL},
3521
3522         /*
3523          * Other matching rules
3524          */
3525         
3526         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
3527                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3528                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3529                 NULL, NULL, octetStringMatch,
3530                 octetStringIndexer, octetStringFilter,
3531                 NULL },
3532
3533         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
3534                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3535                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3536                 NULL, dnNormalize, dnMatch,
3537                 octetStringIndexer, octetStringFilter,
3538                 NULL },
3539
3540         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
3541                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3542                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3543                 NULL, dnNormalize, dnRelativeMatch,
3544                 NULL, NULL,
3545                 NULL },
3546
3547         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
3548                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3549                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3550                 NULL, dnNormalize, dnRelativeMatch,
3551                 NULL, NULL,
3552                 NULL },
3553
3554         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
3555                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3556                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3557                 NULL, dnNormalize, dnRelativeMatch,
3558                 NULL, NULL,
3559                 NULL },
3560
3561         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
3562                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3563                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3564                 NULL, dnNormalize, dnRelativeMatch,
3565                 NULL, NULL,
3566                 NULL },
3567
3568         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
3569                 "SYNTAX 1.2.36.79672281.1.5.0 )",
3570                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3571                 NULL, rdnNormalize, rdnMatch,
3572                 octetStringIndexer, octetStringFilter,
3573                 NULL },
3574
3575 #ifdef LDAP_COMP_MATCH
3576         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
3577                 "SYNTAX 1.2.36.79672281.1.5.2 )",
3578                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
3579                 NULL, NULL , componentFilterMatch,
3580                 octetStringIndexer, octetStringFilter,
3581                 NULL },
3582
3583         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
3584                 "SYNTAX 1.2.36.79672281.1.5.3 )",
3585                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
3586                 NULL, NULL , allComponentsMatch,
3587                 octetStringIndexer, octetStringFilter,
3588                 NULL },
3589
3590         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
3591                 "SYNTAX 1.2.36.79672281.1.5.3 )",
3592                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
3593                 NULL, NULL , directoryComponentsMatch,
3594                 octetStringIndexer, octetStringFilter,
3595                 NULL },
3596 #endif
3597
3598         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
3599                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3600                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3601                 NULL, UTF8StringNormalize, octetStringMatch,
3602                 octetStringIndexer, octetStringFilter,
3603                 directoryStringApproxMatchOID },
3604
3605         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
3606                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3607                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3608                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3609                 NULL, NULL,
3610                 "caseIgnoreMatch" },
3611
3612         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
3613                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3614                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3615                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
3616                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3617                 "caseIgnoreMatch" },
3618
3619         {"( 2.5.13.5 NAME 'caseExactMatch' "
3620                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3621                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3622                 NULL, UTF8StringNormalize, octetStringMatch,
3623                 octetStringIndexer, octetStringFilter,
3624                 directoryStringApproxMatchOID },
3625
3626         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
3627                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3628                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3629                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3630                 NULL, NULL,
3631                 "caseExactMatch" },
3632
3633         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
3634                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3635                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3636                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
3637                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3638                 "caseExactMatch" },
3639
3640         {"( 2.5.13.8 NAME 'numericStringMatch' "
3641                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3642                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3643                 NULL, numericStringNormalize, octetStringMatch,
3644                 octetStringIndexer, octetStringFilter,
3645                 NULL },
3646
3647         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
3648                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3649                 SLAP_MR_ORDERING, NULL,
3650                 NULL, numericStringNormalize, octetStringOrderingMatch,
3651                 NULL, NULL,
3652                 "numericStringMatch" },
3653
3654         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
3655                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3656                 SLAP_MR_SUBSTR, NULL,
3657                 NULL, numericStringNormalize, octetStringSubstringsMatch,
3658                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3659                 "numericStringMatch" },
3660
3661         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
3662                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
3663                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3664                 NULL, NULL, NULL, NULL, NULL, NULL },
3665
3666         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
3667                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3668                 SLAP_MR_SUBSTR, NULL,
3669                 NULL, NULL, NULL, NULL, NULL,
3670                 "caseIgnoreListMatch" },
3671
3672         {"( 2.5.13.13 NAME 'booleanMatch' "
3673                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
3674                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3675                 NULL, NULL, booleanMatch,
3676                 octetStringIndexer, octetStringFilter,
3677                 NULL },
3678
3679         {"( 2.5.13.14 NAME 'integerMatch' "
3680                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3681                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3682                 NULL, NULL, integerMatch,
3683                 octetStringIndexer, octetStringFilter,
3684                 NULL },
3685
3686         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
3687                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3688                 SLAP_MR_ORDERING, NULL,
3689                 NULL, NULL, integerMatch,
3690                 NULL, NULL,
3691                 "integerMatch" },
3692
3693         {"( 2.5.13.16 NAME 'bitStringMatch' "
3694                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
3695                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3696                 NULL, NULL, octetStringMatch,
3697                 octetStringIndexer, octetStringFilter,
3698                 NULL },
3699
3700         {"( 2.5.13.17 NAME 'octetStringMatch' "
3701                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3702                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3703                 NULL, NULL, octetStringMatch,
3704                 octetStringIndexer, octetStringFilter,
3705                 NULL },
3706
3707         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
3708                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3709                 SLAP_MR_ORDERING, NULL,
3710                 NULL, NULL, octetStringOrderingMatch,
3711                 NULL, NULL,
3712                 "octetStringMatch" },
3713
3714         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
3715                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3716                 SLAP_MR_SUBSTR, NULL,
3717                 NULL, NULL, octetStringSubstringsMatch,
3718                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3719                 "octetStringMatch" },
3720
3721         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
3722                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
3723                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3724                 NULL,
3725                 telephoneNumberNormalize, octetStringMatch,
3726                 octetStringIndexer, octetStringFilter,
3727                 NULL },
3728
3729         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
3730                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3731                 SLAP_MR_SUBSTR, NULL,
3732                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
3733                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3734                 "telephoneNumberMatch" },
3735
3736         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
3737                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
3738                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3739                 NULL, NULL, NULL, NULL, NULL, NULL },
3740
3741         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
3742                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
3743                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3744                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
3745                 uniqueMemberIndexer, uniqueMemberFilter,
3746                 NULL },
3747
3748         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
3749                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
3750                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3751                 NULL, NULL, NULL, NULL, NULL, NULL },
3752
3753         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
3754                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3755                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
3756                 NULL, generalizedTimeNormalize, octetStringMatch,
3757                 generalizedTimeIndexer, generalizedTimeFilter,
3758                 NULL },
3759
3760         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
3761                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3762                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
3763                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
3764                 NULL, NULL,
3765                 "generalizedTimeMatch" },
3766
3767         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
3768                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3769                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3770                         integerFirstComponentMatchSyntaxes,
3771                 NULL, firstComponentNormalize, integerMatch,
3772                 octetStringIndexer, octetStringFilter,
3773                 NULL },
3774
3775         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
3776                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3777                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3778                         objectIdentifierFirstComponentMatchSyntaxes,
3779                 NULL, firstComponentNormalize, octetStringMatch,
3780                 octetStringIndexer, octetStringFilter,
3781                 NULL },
3782
3783         {"( 2.5.13.34 NAME 'certificateExactMatch' "
3784                 "SYNTAX 1.2.826.0.1.3344810.7.1 )",
3785                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
3786 #ifdef HAVE_TLS
3787                 NULL, certificateExactNormalize, octetStringMatch,
3788                 octetStringIndexer, octetStringFilter,
3789 #else
3790                 NULL, NULL, NULL, NULL, NULL,
3791 #endif
3792                 NULL },
3793
3794         {"( 2.5.13.35 NAME 'certificateMatch' "
3795                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )",
3796                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3797 #ifdef HAVE_TLS
3798                 NULL, NULL, octetStringMatch,
3799                 octetStringIndexer, octetStringFilter,
3800 #else
3801                 NULL, NULL, NULL, NULL, NULL,
3802 #endif
3803                 NULL },
3804
3805         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
3806                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3807                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3808                 NULL, IA5StringNormalize, octetStringMatch,
3809                 octetStringIndexer, octetStringFilter,
3810                 IA5StringApproxMatchOID },
3811
3812         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
3813                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3814                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3815                 NULL, IA5StringNormalize, octetStringMatch,
3816                 octetStringIndexer, octetStringFilter,
3817                 IA5StringApproxMatchOID },
3818
3819         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
3820                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3821                 SLAP_MR_SUBSTR, NULL,
3822                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
3823                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3824                 "caseIgnoreIA5Match" },
3825
3826         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
3827                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3828                 SLAP_MR_SUBSTR, NULL,
3829                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
3830                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3831                 "caseExactIA5Match" },
3832
3833 #ifdef SLAPD_AUTHPASSWD
3834         /* needs updating */
3835         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
3836                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3837                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3838                 NULL, NULL, authPasswordMatch,
3839                 NULL, NULL,
3840                 NULL},
3841 #endif
3842
3843         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
3844                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3845                 SLAP_MR_EXT, NULL,
3846                 NULL, NULL, integerBitAndMatch,
3847                 NULL, NULL,
3848                 "integerMatch" },
3849
3850         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
3851                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3852                 SLAP_MR_EXT, NULL,
3853                 NULL, NULL, integerBitOrMatch,
3854                 NULL, NULL,
3855                 "integerMatch" },
3856
3857         {"( 1.3.6.1.4.1.4203.666.4.6 NAME 'UUIDMatch' "
3858                 "SYNTAX 1.3.6.1.4.1.4203.666.2.6 )",
3859                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3860                 NULL, UUIDNormalize, octetStringMatch,
3861                 octetStringIndexer, octetStringFilter,
3862                 NULL},
3863
3864         {"( 1.3.6.1.4.1.4203.666.4.7 NAME 'UUIDOrderingMatch' "
3865                 "SYNTAX 1.3.6.1.4.1.4203.666.2.6 )",
3866                 SLAP_MR_HIDE | SLAP_MR_ORDERING, NULL,
3867                 NULL, UUIDNormalize, octetStringOrderingMatch,
3868                 octetStringIndexer, octetStringFilter,
3869                 "UUIDMatch"},
3870
3871         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
3872                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
3873                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
3874                 NULL, NULL, csnMatch,
3875                 csnIndexer, csnFilter,
3876                 NULL},
3877
3878         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
3879                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
3880                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
3881                 NULL, NULL, csnOrderingMatch,
3882                 NULL, NULL,
3883                 "CSNMatch" },
3884
3885 #ifdef SLAP_AUTHZ_SYNTAX
3886         /* FIXME: OID is unused, but not registered yet */
3887         {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
3888                 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
3889                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3890                 NULL, authzNormalize, authzMatch,
3891                 NULL, NULL,
3892                 NULL},
3893 #endif /* SLAP_AUTHZ_SYNTAX */
3894
3895         {NULL, SLAP_MR_NONE, NULL,
3896                 NULL, NULL, NULL, NULL, NULL,
3897                 NULL }
3898 };
3899
3900 int
3901 slap_schema_init( void )
3902 {
3903         int             res;
3904         int             i;
3905
3906         /* we should only be called once (from main) */
3907         assert( schema_init_done == 0 );
3908
3909         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
3910                 res = register_syntax( &syntax_defs[i] );
3911
3912                 if ( res ) {
3913                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
3914                                  syntax_defs[i].sd_desc );
3915                         return LDAP_OTHER;
3916                 }
3917         }
3918
3919         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
3920                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
3921                         mrule_defs[i].mrd_compat_syntaxes == NULL )
3922                 {
3923                         fprintf( stderr,
3924                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
3925                                  mrule_defs[i].mrd_desc );
3926                         continue;
3927                 }
3928
3929                 res = register_matching_rule( &mrule_defs[i] );
3930
3931                 if ( res ) {
3932                         fprintf( stderr,
3933                                 "slap_schema_init: Error registering matching rule %s\n",
3934                                  mrule_defs[i].mrd_desc );
3935                         return LDAP_OTHER;
3936                 }
3937         }
3938
3939         res = slap_schema_load();
3940         schema_init_done = 1;
3941         return res;
3942 }
3943
3944 void
3945 schema_destroy( void )
3946 {
3947         oidm_destroy();
3948         oc_destroy();
3949         at_destroy();
3950         mr_destroy();
3951         mru_destroy();
3952         syn_destroy();
3953
3954         ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
3955         ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
3956 }