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