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