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