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