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