]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
now I remember why I introduced the 'has_ldapinfo_dn_ru' flag
[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 static int
742 nameUIDValidate(
743         Syntax *syntax,
744         struct berval *in )
745 {
746         int rc;
747         struct berval dn;
748
749         if( in->bv_len == 0 ) return LDAP_SUCCESS;
750
751         ber_dupbv( &dn, in );
752         if( !dn.bv_val ) return LDAP_OTHER;
753
754         if( dn.bv_val[dn.bv_len-1] == 'B'
755                 && dn.bv_val[dn.bv_len-2] == '\'' )
756         {
757                 /* assume presence of optional UID */
758                 ber_len_t i;
759
760                 for(i=dn.bv_len-3; i>1; i--) {
761                         if( dn.bv_val[i] != '0' && dn.bv_val[i] != '1' ) {
762                                 break;
763                         }
764                 }
765                 if( dn.bv_val[i] != '\'' || dn.bv_val[i-1] != '#' ) {
766                         ber_memfree( dn.bv_val );
767                         return LDAP_INVALID_SYNTAX;
768                 }
769
770                 /* trim the UID to allow use of dnValidate */
771                 dn.bv_val[i-1] = '\0';
772                 dn.bv_len = i-1;
773         }
774
775         rc = dnValidate( NULL, &dn );
776
777         ber_memfree( dn.bv_val );
778         return rc;
779 }
780
781 int
782 nameUIDPretty(
783         Syntax *syntax,
784         struct berval *val,
785         struct berval *out,
786         void *ctx )
787 {
788         assert( val );
789         assert( out );
790
791
792 #ifdef NEW_LOGGING
793         LDAP_LOG( OPERATION, ARGS, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
794 #else
795         Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
796 #endif
797
798         if( val->bv_len == 0 ) {
799                 ber_dupbv_x( out, val, ctx );
800
801         } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
802                 return LDAP_INVALID_SYNTAX;
803
804         } else {
805                 int rc;
806                 struct berval dnval = *val;
807                 struct berval uidval = { 0, NULL };
808
809                 if( val->bv_val[val->bv_len-1] == 'B'
810                         && val->bv_val[val->bv_len-2] == '\'' )
811                 {
812                         uidval.bv_val=strrchr( val->bv_val, '#' );
813                         if( uidval.bv_val ) {
814                                 dnval.bv_len = uidval.bv_val - dnval.bv_val;
815                                 uidval.bv_len = val->bv_len - dnval.bv_len;
816
817                                 uidval.bv_len--;
818                                 uidval.bv_val++;
819                         }
820                 }
821
822                 rc = dnPretty( syntax, &dnval, out, ctx );
823                 if( rc != LDAP_SUCCESS ) return rc;
824
825                 if( uidval.bv_val ) {
826                         char *tmp = sl_realloc( out->bv_val, out->bv_len + uidval.bv_len + 2, ctx );
827                         int i, c, got1;
828                         if( tmp == NULL ) {
829                                 ber_memfree_x( out->bv_val, ctx );
830                                 return LDAP_OTHER;
831                         }
832                         out->bv_val = tmp;
833                         out->bv_val[out->bv_len++] = '#';
834
835                         got1 = uidval.bv_len < sizeof("'0'B"); 
836                         for(i=0; i<uidval.bv_len; i++) {
837                                 c = uidval.bv_val[i];
838                                 switch(c) {
839                                         case '0':
840                                                 if( got1 ) out->bv_val[out->bv_len++] = c;
841                                                 break;
842                                         case '1':
843                                                 got1 = 1;
844                                         default:
845                                                 out->bv_val[out->bv_len++] = c;
846                                 }
847                         }
848
849                         out->bv_val[out->bv_len] = '\0';
850                 }
851         }
852
853 #ifdef NEW_LOGGING
854         LDAP_LOG( OPERATION, ARGS, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
855 #else
856         Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
857 #endif
858
859         return LDAP_SUCCESS;
860 }
861
862 static int
863 uniqueMemberNormalize(
864         slap_mask_t usage,
865         Syntax *syntax,
866         MatchingRule *mr,
867         struct berval *val,
868         struct berval *normalized,
869         void *ctx )
870 {
871         struct berval out;
872         int rc;
873
874         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ));
875
876         ber_dupbv( &out, val );
877         if( out.bv_len != 0 ) {
878                 struct berval uid = { 0, NULL };
879
880                 if( out.bv_val[out.bv_len-1] == 'B'
881                         && out.bv_val[out.bv_len-2] == '\'' )
882                 {
883                         /* assume presence of optional UID */
884                         uid.bv_val = strrchr( out.bv_val, '#' );
885
886                         if( uid.bv_val == NULL ) {
887                                 free( out.bv_val );
888                                 return LDAP_INVALID_SYNTAX;
889                         }
890
891                         uid.bv_len = out.bv_len - (uid.bv_val - out.bv_val);
892                         out.bv_len -= uid.bv_len--;
893
894                         /* temporarily trim the UID */
895                         *(uid.bv_val++) = '\0';
896                 }
897
898                 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
899
900                 if( rc != LDAP_SUCCESS ) {
901                         free( out.bv_val );
902                         return LDAP_INVALID_SYNTAX;
903                 }
904
905                 if( uid.bv_len ) {
906                         normalized->bv_val = ch_realloc( normalized->bv_val,
907                                 normalized->bv_len + uid.bv_len + sizeof("#") );
908
909                         /* insert the separator */
910                         normalized->bv_val[normalized->bv_len++] = '#';
911
912                         /* append the UID */
913                         AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
914                                 uid.bv_val, uid.bv_len );
915                         normalized->bv_len += uid.bv_len;
916
917                         /* terminate */
918                         normalized->bv_val[normalized->bv_len] = '\0';
919                 }
920
921                 free( out.bv_val );
922         }
923
924         return LDAP_SUCCESS;
925 }
926
927 static int
928 uniqueMemberMatch(
929         int *matchp,
930         slap_mask_t flags,
931         Syntax *syntax,
932         MatchingRule *mr,
933         struct berval *value,
934         void *assertedValue )
935 {
936         int match;
937         struct berval *asserted = (struct berval *) assertedValue;
938         struct berval assertedDN = { 0, NULL };
939         struct berval assertedUID = { 0, NULL };
940         struct berval valueDN = { 0, NULL };
941         struct berval valueUID = { 0, NULL };
942
943         if( asserted->bv_len != 0 ) {
944                 assertedDN = *asserted;
945
946                 if( assertedDN.bv_val[assertedDN.bv_len-1] == 'B'
947                         && assertedDN.bv_val[assertedDN.bv_len-2] == '\'' )
948                 {
949                         /* assume presence of optional UID */
950                         assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
951
952                         if( assertedUID.bv_val == NULL ) {
953                                 return LDAP_INVALID_SYNTAX;
954                         }
955
956                         assertedUID.bv_len = assertedDN.bv_len -
957                                 (assertedUID.bv_val - assertedDN.bv_val);
958                         assertedDN.bv_len -= assertedUID.bv_len--;
959
960                         /* trim the separator */
961                         assertedUID.bv_val++;
962                 }
963         }
964
965         if( value->bv_len != 0 ) {
966                 valueDN = *value;
967
968                 if( valueDN.bv_val[valueDN.bv_len-1] == 'B'
969                         && valueDN.bv_val[valueDN.bv_len-2] == '\'' )
970                 {
971                         /* assume presence of optional UID */
972                         valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
973
974                         if( valueUID.bv_val == NULL ) {
975                                 return LDAP_INVALID_SYNTAX;
976                         }
977
978                         valueUID.bv_len = valueDN.bv_len -
979                                 (assertedUID.bv_val - assertedDN.bv_val);
980                         valueDN.bv_len -= valueUID.bv_len--;
981
982                         /* trim the separator */
983                         valueUID.bv_val++;
984                 }
985         }
986
987         if( valueUID.bv_len && assertedUID.bv_len ) {
988                 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
989                 if( match ) {
990                         *matchp = match;
991                         return LDAP_SUCCESS;
992                 }
993         }
994
995         return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
996 }
997
998 /*
999  * Handling boolean syntax and matching is quite rigid.
1000  * A more flexible approach would be to allow a variety
1001  * of strings to be normalized and prettied into TRUE
1002  * and FALSE.
1003  */
1004 static int
1005 booleanValidate(
1006         Syntax *syntax,
1007         struct berval *in )
1008 {
1009         /* very unforgiving validation, requires no normalization
1010          * before simplistic matching
1011          */
1012
1013         if( in->bv_len == 4 ) {
1014                 if( bvmatch( in, &slap_true_bv ) ) {
1015                         return LDAP_SUCCESS;
1016                 }
1017         } else if( in->bv_len == 5 ) {
1018                 if( bvmatch( in, &slap_false_bv ) ) {
1019                         return LDAP_SUCCESS;
1020                 }
1021         }
1022
1023         return LDAP_INVALID_SYNTAX;
1024 }
1025
1026 static int
1027 booleanMatch(
1028         int *matchp,
1029         slap_mask_t flags,
1030         Syntax *syntax,
1031         MatchingRule *mr,
1032         struct berval *value,
1033         void *assertedValue )
1034 {
1035         /* simplistic matching allowed by rigid validation */
1036         struct berval *asserted = (struct berval *) assertedValue;
1037         *matchp = value->bv_len != asserted->bv_len;
1038         return LDAP_SUCCESS;
1039 }
1040
1041 /*-------------------------------------------------------------------
1042 LDAP/X.500 string syntax / matching rules have a few oddities.  This
1043 comment attempts to detail how slapd(8) treats them.
1044
1045 Summary:
1046   StringSyntax          X.500   LDAP    Matching/Comments
1047   DirectoryString       CHOICE  UTF8    i/e + ignore insignificant spaces
1048   PrintableString       subset  subset  i/e + ignore insignificant spaces
1049   PrintableString       subset  subset  i/e + ignore insignificant spaces
1050   NumericString         subset  subset  ignore all spaces
1051   IA5String                     ASCII   ASCII   i/e + ignore insignificant spaces
1052   TeletexString         T.61    T.61    i/e + ignore insignificant spaces
1053
1054   TelephoneNumber       subset  subset  i + ignore all spaces and "-"
1055
1056   See draft-ietf-ldapbis-strpro for details (once published).
1057
1058
1059 Directory String -
1060   In X.500(93), a directory string can be either a PrintableString,
1061   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1062   In later versions, more CHOICEs were added.  In all cases the string
1063   must be non-empty.
1064
1065   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1066   A directory string cannot be zero length.
1067
1068   For matching, there are both case ignore and exact rules.  Both
1069   also require that "insignificant" spaces be ignored.
1070         spaces before the first non-space are ignored;
1071         spaces after the last non-space are ignored;
1072         spaces after a space are ignored.
1073   Note: by these rules (and as clarified in X.520), a string of only
1074   spaces is to be treated as if held one space, not empty (which
1075   would be a syntax error).
1076
1077 NumericString
1078   In ASN.1, numeric string is just a string of digits and spaces
1079   and could be empty.  However, in X.500, all attribute values of
1080   numeric string carry a non-empty constraint.  For example:
1081
1082         internationalISDNNumber ATTRIBUTE ::= {
1083                 WITH SYNTAX InternationalISDNNumber
1084                 EQUALITY MATCHING RULE numericStringMatch
1085                 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1086                 ID id-at-internationalISDNNumber }
1087         InternationalISDNNumber ::=
1088             NumericString (SIZE(1..ub-international-isdn-number))
1089
1090   Unforunately, some assertion values are don't carry the same
1091   constraint (but its unclear how such an assertion could ever
1092   be true). In LDAP, there is one syntax (numericString) not two
1093   (numericString with constraint, numericString without constraint).
1094   This should be treated as numericString with non-empty constraint.
1095   Note that while someone may have no ISDN number, there are no ISDN
1096   numbers which are zero length.
1097
1098   In matching, spaces are ignored.
1099
1100 PrintableString
1101   In ASN.1, Printable string is just a string of printable characters
1102   and can be empty.  In X.500, semantics much like NumericString (see
1103   serialNumber for a like example) excepting uses insignificant space
1104   handling instead of ignore all spaces.  
1105
1106 IA5String
1107   Basically same as PrintableString.  There are no examples in X.500,
1108   but same logic applies.  So we require them to be non-empty as
1109   well.
1110
1111 -------------------------------------------------------------------*/
1112
1113 static int
1114 UTF8StringValidate(
1115         Syntax *syntax,
1116         struct berval *in )
1117 {
1118         ber_len_t count;
1119         int len;
1120         unsigned char *u = (unsigned char *)in->bv_val;
1121
1122         if( in->bv_len == 0 && syntax == slap_schema.si_syn_directoryString ) {
1123                 /* directory strings cannot be empty */
1124                 return LDAP_INVALID_SYNTAX;
1125         }
1126
1127         for( count = in->bv_len; count > 0; count-=len, u+=len ) {
1128                 /* get the length indicated by the first byte */
1129                 len = LDAP_UTF8_CHARLEN2( u, len );
1130
1131                 /* very basic checks */
1132                 switch( len ) {
1133                         case 6:
1134                                 if( (u[5] & 0xC0) != 0x80 ) {
1135                                         return LDAP_INVALID_SYNTAX;
1136                                 }
1137                         case 5:
1138                                 if( (u[4] & 0xC0) != 0x80 ) {
1139                                         return LDAP_INVALID_SYNTAX;
1140                                 }
1141                         case 4:
1142                                 if( (u[3] & 0xC0) != 0x80 ) {
1143                                         return LDAP_INVALID_SYNTAX;
1144                                 }
1145                         case 3:
1146                                 if( (u[2] & 0xC0 )!= 0x80 ) {
1147                                         return LDAP_INVALID_SYNTAX;
1148                                 }
1149                         case 2:
1150                                 if( (u[1] & 0xC0) != 0x80 ) {
1151                                         return LDAP_INVALID_SYNTAX;
1152                                 }
1153                         case 1:
1154                                 /* CHARLEN already validated it */
1155                                 break;
1156                         default:
1157                                 return LDAP_INVALID_SYNTAX;
1158                 }
1159
1160                 /* make sure len corresponds with the offset
1161                         to the next character */
1162                 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1163         }
1164
1165         if( count != 0 ) {
1166                 return LDAP_INVALID_SYNTAX;
1167         }
1168
1169         return LDAP_SUCCESS;
1170 }
1171
1172 static int
1173 UTF8StringNormalize(
1174         slap_mask_t use,
1175         Syntax *syntax,
1176         MatchingRule *mr,
1177         struct berval *val,
1178         struct berval *normalized,
1179         void *ctx )
1180 {
1181         struct berval tmp, nvalue;
1182         int flags;
1183         int i, wasspace;
1184
1185         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
1186
1187         if( val->bv_val == NULL ) {
1188                 /* assume we're dealing with a syntax (e.g., UTF8String)
1189                  * which allows empty strings
1190                  */
1191                 normalized->bv_len = 0;
1192                 normalized->bv_val = NULL;
1193                 return LDAP_SUCCESS;
1194         }
1195
1196         flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1197                 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1198         flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1199                 ? LDAP_UTF8_APPROX : 0;
1200
1201         val = UTF8bvnormalize( val, &tmp, flags, ctx );
1202         if( val == NULL ) {
1203                 return LDAP_OTHER;
1204         }
1205         
1206         /* collapse spaces (in place) */
1207         nvalue.bv_len = 0;
1208         nvalue.bv_val = tmp.bv_val;
1209
1210         wasspace=1; /* trim leading spaces */
1211         for( i=0; i<tmp.bv_len; i++) {
1212                 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1213                         if( wasspace++ == 0 ) {
1214                                 /* trim repeated spaces */
1215                                 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1216                         }
1217                 } else {
1218                         wasspace = 0;
1219                         nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1220                 }
1221         }
1222
1223         if( nvalue.bv_len ) {
1224                 if( wasspace ) {
1225                         /* last character was a space, trim it */
1226                         --nvalue.bv_len;
1227                 }
1228                 nvalue.bv_val[nvalue.bv_len] = '\0';
1229
1230         } else {
1231                 /* string of all spaces is treated as one space */
1232                 nvalue.bv_val[0] = ' ';
1233                 nvalue.bv_val[1] = '\0';
1234                 nvalue.bv_len = 1;
1235         }
1236
1237         *normalized = nvalue;
1238         return LDAP_SUCCESS;
1239 }
1240
1241 #if defined(SLAPD_APPROX_INITIALS)
1242 #       define SLAPD_APPROX_DELIMITER "._ "
1243 #       define SLAPD_APPROX_WORDLEN 2
1244 #else
1245 #       define SLAPD_APPROX_DELIMITER " "
1246 #       define SLAPD_APPROX_WORDLEN 1
1247 #endif
1248
1249 static int
1250 approxMatch(
1251         int *matchp,
1252         slap_mask_t flags,
1253         Syntax *syntax,
1254         MatchingRule *mr,
1255         struct berval *value,
1256         void *assertedValue )
1257 {
1258         struct berval *nval, *assertv;
1259         char *val, **values, **words, *c;
1260         int i, count, len, nextchunk=0, nextavail=0;
1261
1262         /* Yes, this is necessary */
1263         nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
1264         if( nval == NULL ) {
1265                 *matchp = 1;
1266                 return LDAP_SUCCESS;
1267         }
1268
1269         /* Yes, this is necessary */
1270         assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1271                 NULL, LDAP_UTF8_APPROX, NULL );
1272         if( assertv == NULL ) {
1273                 ber_bvfree( nval );
1274                 *matchp = 1;
1275                 return LDAP_SUCCESS;
1276         }
1277
1278         /* Isolate how many words there are */
1279         for ( c = nval->bv_val, count = 1; *c; c++ ) {
1280                 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1281                 if ( c == NULL ) break;
1282                 *c = '\0';
1283                 count++;
1284         }
1285
1286         /* Get a phonetic copy of each word */
1287         words = (char **)ch_malloc( count * sizeof(char *) );
1288         values = (char **)ch_malloc( count * sizeof(char *) );
1289         for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
1290                 words[i] = c;
1291                 values[i] = phonetic(c);
1292         }
1293
1294         /* Work through the asserted value's words, to see if at least some
1295            of the words are there, in the same order. */
1296         len = 0;
1297         while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1298                 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1299                 if( len == 0 ) {
1300                         nextchunk++;
1301                         continue;
1302                 }
1303 #if defined(SLAPD_APPROX_INITIALS)
1304                 else if( len == 1 ) {
1305                         /* Single letter words need to at least match one word's initial */
1306                         for( i=nextavail; i<count; i++ )
1307                                 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1308                                         nextavail=i+1;
1309                                         break;
1310                                 }
1311                 }
1312 #endif
1313                 else {
1314                         /* Isolate the next word in the asserted value and phonetic it */
1315                         assertv->bv_val[nextchunk+len] = '\0';
1316                         val = phonetic( assertv->bv_val + nextchunk );
1317
1318                         /* See if this phonetic chunk is in the remaining words of *value */
1319                         for( i=nextavail; i<count; i++ ){
1320                                 if( !strcmp( val, values[i] ) ){
1321                                         nextavail = i+1;
1322                                         break;
1323                                 }
1324                         }
1325                         ch_free( val );
1326                 }
1327
1328                 /* This chunk in the asserted value was NOT within the *value. */
1329                 if( i >= count ) {
1330                         nextavail=-1;
1331                         break;
1332                 }
1333
1334                 /* Go on to the next word in the asserted value */
1335                 nextchunk += len+1;
1336         }
1337
1338         /* If some of the words were seen, call it a match */
1339         if( nextavail > 0 ) {
1340                 *matchp = 0;
1341         }
1342         else {
1343                 *matchp = 1;
1344         }
1345
1346         /* Cleanup allocs */
1347         ber_bvfree( assertv );
1348         for( i=0; i<count; i++ ) {
1349                 ch_free( values[i] );
1350         }
1351         ch_free( values );
1352         ch_free( words );
1353         ber_bvfree( nval );
1354
1355         return LDAP_SUCCESS;
1356 }
1357
1358 static int 
1359 approxIndexer(
1360         slap_mask_t use,
1361         slap_mask_t flags,
1362         Syntax *syntax,
1363         MatchingRule *mr,
1364         struct berval *prefix,
1365         BerVarray values,
1366         BerVarray *keysp,
1367         void *ctx )
1368 {
1369         char *c;
1370         int i,j, len, wordcount, keycount=0;
1371         struct berval *newkeys;
1372         BerVarray keys=NULL;
1373
1374         for( j=0; values[j].bv_val != NULL; j++ ) {
1375                 struct berval val = { 0, NULL };
1376                 /* Yes, this is necessary */
1377                 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
1378                 assert( val.bv_val != NULL );
1379
1380                 /* Isolate how many words there are. There will be a key for each */
1381                 for( wordcount = 0, c = val.bv_val; *c; c++) {
1382                         len = strcspn(c, SLAPD_APPROX_DELIMITER);
1383                         if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1384                         c+= len;
1385                         if (*c == '\0') break;
1386                         *c = '\0';
1387                 }
1388
1389                 /* Allocate/increase storage to account for new keys */
1390                 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
1391                         * sizeof(struct berval) );
1392                 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1393                 if( keys ) ch_free( keys );
1394                 keys = newkeys;
1395
1396                 /* Get a phonetic copy of each word */
1397                 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1398                         len = strlen( c );
1399                         if( len < SLAPD_APPROX_WORDLEN ) continue;
1400                         ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1401                         keycount++;
1402                         i++;
1403                 }
1404
1405                 ber_memfree( val.bv_val );
1406         }
1407         keys[keycount].bv_val = NULL;
1408         *keysp = keys;
1409
1410         return LDAP_SUCCESS;
1411 }
1412
1413 static int 
1414 approxFilter(
1415         slap_mask_t use,
1416         slap_mask_t flags,
1417         Syntax *syntax,
1418         MatchingRule *mr,
1419         struct berval *prefix,
1420         void * assertedValue,
1421         BerVarray *keysp,
1422         void *ctx )
1423 {
1424         char *c;
1425         int i, count, len;
1426         struct berval *val;
1427         BerVarray keys;
1428
1429         /* Yes, this is necessary */
1430         val = UTF8bvnormalize( ((struct berval *)assertedValue),
1431                 NULL, LDAP_UTF8_APPROX, NULL );
1432         if( val == NULL || val->bv_val == NULL ) {
1433                 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1434                 keys[0].bv_val = NULL;
1435                 *keysp = keys;
1436                 ber_bvfree( val );
1437                 return LDAP_SUCCESS;
1438         }
1439
1440         /* Isolate how many words there are. There will be a key for each */
1441         for( count = 0,c = val->bv_val; *c; c++) {
1442                 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1443                 if( len >= SLAPD_APPROX_WORDLEN ) count++;
1444                 c+= len;
1445                 if (*c == '\0') break;
1446                 *c = '\0';
1447         }
1448
1449         /* Allocate storage for new keys */
1450         keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1451
1452         /* Get a phonetic copy of each word */
1453         for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1454                 len = strlen(c);
1455                 if( len < SLAPD_APPROX_WORDLEN ) continue;
1456                 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1457                 i++;
1458         }
1459
1460         ber_bvfree( val );
1461
1462         keys[count].bv_val = NULL;
1463         *keysp = keys;
1464
1465         return LDAP_SUCCESS;
1466 }
1467
1468 /* Remove all spaces and '-' characters */
1469 static int
1470 telephoneNumberNormalize(
1471         slap_mask_t usage,
1472         Syntax *syntax,
1473         MatchingRule *mr,
1474         struct berval *val,
1475         struct berval *normalized,
1476         void *ctx )
1477 {
1478         char *p, *q;
1479
1480         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ));
1481
1482         /* validator should have refused an empty string */
1483         assert( val->bv_len );
1484
1485         q = normalized->bv_val = sl_malloc( val->bv_len + 1, ctx );
1486
1487         for( p = val->bv_val; *p; p++ ) {
1488                 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1489                         *q++ = *p;
1490                 }
1491         }
1492         *q = '\0';
1493
1494         normalized->bv_len = q - normalized->bv_val;
1495
1496         if( normalized->bv_len == 0 ) {
1497                 sl_free( normalized->bv_val, ctx );
1498                 normalized->bv_val = NULL;
1499                 return LDAP_INVALID_SYNTAX;
1500         }
1501
1502         return LDAP_SUCCESS;
1503 }
1504
1505 static int
1506 numericoidValidate(
1507         Syntax *syntax,
1508         struct berval *in )
1509 {
1510         struct berval val = *in;
1511
1512         if( val.bv_len == 0 ) {
1513                 /* disallow empty strings */
1514                 return LDAP_INVALID_SYNTAX;
1515         }
1516
1517         while( OID_LEADCHAR( val.bv_val[0] ) ) {
1518                 if ( val.bv_len == 1 ) {
1519                         return LDAP_SUCCESS;
1520                 }
1521
1522                 if ( val.bv_val[0] == '0' ) {
1523                         break;
1524                 }
1525
1526                 val.bv_val++;
1527                 val.bv_len--;
1528
1529                 while ( OID_LEADCHAR( val.bv_val[0] )) {
1530                         val.bv_val++;
1531                         val.bv_len--;
1532
1533                         if ( val.bv_len == 0 ) {
1534                                 return LDAP_SUCCESS;
1535                         }
1536                 }
1537
1538                 if( !OID_SEPARATOR( val.bv_val[0] )) {
1539                         break;
1540                 }
1541
1542                 val.bv_val++;
1543                 val.bv_len--;
1544         }
1545
1546         return LDAP_INVALID_SYNTAX;
1547 }
1548
1549 static int
1550 integerValidate(
1551         Syntax *syntax,
1552         struct berval *in )
1553 {
1554         ber_len_t i;
1555         struct berval val = *in;
1556
1557         if( val.bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1558
1559         if ( val.bv_val[0] == '-' ) {
1560                 val.bv_len--;
1561                 val.bv_val++;
1562
1563                 if( val.bv_len == 0 ) { /* bare "-" */
1564                         return LDAP_INVALID_SYNTAX;
1565                 }
1566
1567                 if( val.bv_val[0] == '0' ) { /* "-0" */
1568                         return LDAP_INVALID_SYNTAX;
1569                 }
1570
1571         } else if ( val.bv_val[0] == '0' ) {
1572                 if( val.bv_len > 1 ) { /* "0<more>" */
1573                         return LDAP_INVALID_SYNTAX;
1574                 }
1575
1576                 return LDAP_SUCCESS;
1577         }
1578
1579         for( i=0; i < val.bv_len; i++ ) {
1580                 if( !ASCII_DIGIT(val.bv_val[i]) ) {
1581                         return LDAP_INVALID_SYNTAX;
1582                 }
1583         }
1584
1585         return LDAP_SUCCESS;
1586 }
1587
1588 static int
1589 integerMatch(
1590         int *matchp,
1591         slap_mask_t flags,
1592         Syntax *syntax,
1593         MatchingRule *mr,
1594         struct berval *value,
1595         void *assertedValue )
1596 {
1597         struct berval *asserted = (struct berval *) assertedValue;
1598         int vsign = 1, asign = 1;       /* default sign = '+' */
1599         struct berval v, a;
1600         int match;
1601
1602         v = *value;
1603         if( v.bv_val[0] == '-' ) {
1604                 vsign = -1;
1605                 v.bv_val++;
1606                 v.bv_len--;
1607         }
1608
1609         if( v.bv_len == 0 ) vsign = 0;
1610
1611         a = *asserted;
1612         if( a.bv_val[0] == '-' ) {
1613                 asign = -1;
1614                 a.bv_val++;
1615                 a.bv_len--;
1616         }
1617
1618         if( a.bv_len == 0 ) vsign = 0;
1619
1620         match = vsign - asign;
1621         if( match == 0 ) {
1622                 match = ( v.bv_len != a.bv_len
1623                         ? ( v.bv_len < a.bv_len ? -1 : 1 )
1624                         : memcmp( v.bv_val, a.bv_val, v.bv_len ));
1625                 if( vsign < 0 ) match = -match;
1626         }
1627
1628         *matchp = match;
1629         return LDAP_SUCCESS;
1630 }
1631         
1632 static int
1633 countryStringValidate(
1634         Syntax *syntax,
1635         struct berval *val )
1636 {
1637         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
1638
1639         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
1640                 return LDAP_INVALID_SYNTAX;
1641         }
1642         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
1643                 return LDAP_INVALID_SYNTAX;
1644         }
1645
1646         return LDAP_SUCCESS;
1647 }
1648
1649 static int
1650 printableStringValidate(
1651         Syntax *syntax,
1652         struct berval *val )
1653 {
1654         ber_len_t i;
1655
1656         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1657
1658         for(i=0; i < val->bv_len; i++) {
1659                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
1660                         return LDAP_INVALID_SYNTAX;
1661                 }
1662         }
1663
1664         return LDAP_SUCCESS;
1665 }
1666
1667 static int
1668 printablesStringValidate(
1669         Syntax *syntax,
1670         struct berval *val )
1671 {
1672         ber_len_t i, len;
1673
1674         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1675
1676         for(i=0,len=0; i < val->bv_len; i++) {
1677                 int c = val->bv_val[i];
1678
1679                 if( c == '$' ) {
1680                         if( len == 0 ) {
1681                                 return LDAP_INVALID_SYNTAX;
1682                         }
1683                         len = 0;
1684
1685                 } else if ( SLAP_PRINTABLE(c) ) {
1686                         len++;
1687                 } else {
1688                         return LDAP_INVALID_SYNTAX;
1689                 }
1690         }
1691
1692         if( len == 0 ) {
1693                 return LDAP_INVALID_SYNTAX;
1694         }
1695
1696         return LDAP_SUCCESS;
1697 }
1698
1699 static int
1700 IA5StringValidate(
1701         Syntax *syntax,
1702         struct berval *val )
1703 {
1704         ber_len_t i;
1705
1706         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1707
1708         for(i=0; i < val->bv_len; i++) {
1709                 if( !LDAP_ASCII(val->bv_val[i]) ) {
1710                         return LDAP_INVALID_SYNTAX;
1711                 }
1712         }
1713
1714         return LDAP_SUCCESS;
1715 }
1716
1717 static int
1718 IA5StringNormalize(
1719         slap_mask_t use,
1720         Syntax *syntax,
1721         MatchingRule *mr,
1722         struct berval *val,
1723         struct berval *normalized,
1724         void *ctx )
1725 {
1726         char *p, *q;
1727         int casefold = !SLAP_MR_ASSOCIATED(mr, slap_schema.si_mr_caseExactIA5Match);
1728
1729         assert( val->bv_len );
1730
1731         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
1732
1733         p = val->bv_val;
1734
1735         /* Ignore initial whitespace */
1736         while ( ASCII_SPACE( *p ) ) p++;
1737
1738         normalized->bv_val = ber_strdup_x( p, ctx );
1739         p = q = normalized->bv_val;
1740
1741         while ( *p ) {
1742                 if ( ASCII_SPACE( *p ) ) {
1743                         *q++ = *p++;
1744
1745                         /* Ignore the extra whitespace */
1746                         while ( ASCII_SPACE( *p ) ) {
1747                                 p++;
1748                         }
1749
1750                 } else if ( casefold ) {
1751                         /* Most IA5 rules require casefolding */
1752                         *q++ = TOLOWER(*p++);
1753
1754                 } else {
1755                         *q++ = *p++;
1756                 }
1757         }
1758
1759         assert( normalized->bv_val <= p );
1760         assert( q <= p );
1761
1762         /*
1763          * If the string ended in space, backup the pointer one
1764          * position.  One is enough because the above loop collapsed
1765          * all whitespace to a single space.
1766          */
1767         if ( ASCII_SPACE( q[-1] ) ) --q;
1768
1769         /* null terminate */
1770         *q = '\0';
1771
1772         normalized->bv_len = q - normalized->bv_val;
1773         if( normalized->bv_len == 0 ) {
1774                 normalized->bv_val = sl_realloc( normalized->bv_val, 2, ctx );
1775                 normalized->bv_val[0] = ' ';
1776                 normalized->bv_val[1] = '\0';
1777                 normalized->bv_len = 1;
1778         }
1779
1780         return LDAP_SUCCESS;
1781 }
1782
1783 static int
1784 UUIDValidate(
1785         Syntax *syntax,
1786         struct berval *in )
1787 {
1788         int i;
1789         if( in->bv_len != 36 ) {
1790                 assert(0);
1791                 return LDAP_INVALID_SYNTAX;
1792         }
1793
1794         for( i=0; i<36; i++ ) {
1795                 switch(i) {
1796                         case 8:
1797                         case 13:
1798                         case 18:
1799                         case 23:
1800                                 if( in->bv_val[i] != '-' ) {
1801                                         return LDAP_INVALID_SYNTAX;
1802                                 }
1803                                 break;
1804                         default:
1805                                 if( !ASCII_HEX( in->bv_val[i]) ) {
1806                                         return LDAP_INVALID_SYNTAX;
1807                                 }
1808                 }
1809         }
1810         
1811         return LDAP_SUCCESS;
1812 }
1813
1814 static int
1815 UUIDNormalize(
1816         slap_mask_t usage,
1817         Syntax *syntax,
1818         MatchingRule *mr,
1819         struct berval *val,
1820         struct berval *normalized,
1821         void *ctx )
1822 {
1823         unsigned char octet = '\0';
1824         int i;
1825         int j;
1826         normalized->bv_len = 16;
1827         normalized->bv_val = sl_malloc( normalized->bv_len+1, ctx );
1828
1829         for( i=0, j=0; i<36; i++ ) {
1830                 unsigned char nibble;
1831                 if( val->bv_val[i] == '-' ) {
1832                         continue;
1833
1834                 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
1835                         nibble = val->bv_val[i] - '0';
1836
1837                 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
1838                         nibble = val->bv_val[i] - ('a'-10);
1839
1840                 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
1841                         nibble = val->bv_val[i] - ('A'-10);
1842
1843                 } else {
1844                         sl_free( normalized->bv_val, ctx );
1845                         return LDAP_INVALID_SYNTAX;
1846                 }
1847
1848                 if( j & 1 ) {
1849                         octet |= nibble;
1850                         normalized->bv_val[j>>1] = octet;
1851                 } else {
1852                         octet = nibble << 4;
1853                 }
1854                 j++;
1855         }
1856
1857         normalized->bv_val[normalized->bv_len] = 0;
1858         return LDAP_SUCCESS;
1859 }
1860
1861
1862
1863 static int
1864 numericStringValidate(
1865         Syntax *syntax,
1866         struct berval *in )
1867 {
1868         ber_len_t i;
1869
1870         if( in->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1871
1872         for(i=0; i < in->bv_len; i++) {
1873                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
1874                         return LDAP_INVALID_SYNTAX;
1875                 }
1876         }
1877
1878         return LDAP_SUCCESS;
1879 }
1880
1881 static int
1882 numericStringNormalize(
1883         slap_mask_t usage,
1884         Syntax *syntax,
1885         MatchingRule *mr,
1886         struct berval *val,
1887         struct berval *normalized,
1888         void *ctx )
1889 {
1890         /* removal all spaces */
1891         char *p, *q;
1892
1893         assert( val->bv_len );
1894
1895         normalized->bv_val = sl_malloc( val->bv_len + 1, ctx );
1896
1897         p = val->bv_val;
1898         q = normalized->bv_val;
1899
1900         while ( *p ) {
1901                 if ( ASCII_SPACE( *p ) ) {
1902                         /* Ignore whitespace */
1903                         p++;
1904                 } else {
1905                         *q++ = *p++;
1906                 }
1907         }
1908
1909         /* we should have copied no more then is in val */
1910         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
1911
1912         /* null terminate */
1913         *q = '\0';
1914
1915         normalized->bv_len = q - normalized->bv_val;
1916
1917         if( normalized->bv_len == 0 ) {
1918                 normalized->bv_val = sl_realloc( normalized->bv_val, 2, ctx );
1919                 normalized->bv_val[0] = ' ';
1920                 normalized->bv_val[1] = '\0';
1921                 normalized->bv_len = 1;
1922         }
1923
1924         return LDAP_SUCCESS;
1925 }
1926
1927 /*
1928  * Integer conversion macros that will use the largest available
1929  * type.
1930  */
1931 #if defined(HAVE_STRTOLL) && defined(LLONG_MAX) && defined(LLONG_MIN) && defined(HAVE_LONG_LONG)
1932 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
1933 # define SLAP_LONG_MAX       LLONG_MAX
1934 # define SLAP_LONG_MIN       LLONG_MIN
1935 # define SLAP_LONG           long long
1936 #else
1937 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
1938 # define SLAP_LONG_MAX       LONG_MAX
1939 # define SLAP_LONG_MIN       LONG_MIN
1940 # define SLAP_LONG           long
1941 #endif /* HAVE_STRTOLL ... */
1942
1943 static int
1944 integerBitAndMatch(
1945         int *matchp,
1946         slap_mask_t flags,
1947         Syntax *syntax,
1948         MatchingRule *mr,
1949         struct berval *value,
1950         void *assertedValue )
1951 {
1952         SLAP_LONG lValue, lAssertedValue;
1953
1954         /* safe to assume integers are NUL terminated? */
1955         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
1956         if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX) && errno == ERANGE ) {
1957                 return LDAP_CONSTRAINT_VIOLATION;
1958         }
1959
1960         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val, NULL, 10);
1961         if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX )
1962                 && errno == ERANGE )
1963         {
1964                 return LDAP_CONSTRAINT_VIOLATION;
1965         }
1966
1967         *matchp = (lValue & lAssertedValue) ? 0 : 1;
1968         return LDAP_SUCCESS;
1969 }
1970
1971 static int
1972 integerBitOrMatch(
1973         int *matchp,
1974         slap_mask_t flags,
1975         Syntax *syntax,
1976         MatchingRule *mr,
1977         struct berval *value,
1978         void *assertedValue )
1979 {
1980         SLAP_LONG lValue, lAssertedValue;
1981
1982         /* safe to assume integers are NUL terminated? */
1983         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
1984         if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX ) && errno == ERANGE ) {
1985                 return LDAP_CONSTRAINT_VIOLATION;
1986         }
1987
1988         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val, NULL, 10);
1989         if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX )
1990                 && errno == ERANGE )
1991         {
1992                 return LDAP_CONSTRAINT_VIOLATION;
1993         }
1994
1995         *matchp = (lValue | lAssertedValue) ? 0 : -1;
1996         return LDAP_SUCCESS;
1997 }
1998
1999 static int
2000 serialNumberAndIssuerValidate(
2001         Syntax *syntax,
2002         struct berval *in )
2003 {
2004         int rc;
2005         int state;
2006         ber_len_t n;
2007         struct berval sn, i;
2008         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2009
2010         i.bv_val = strchr( in->bv_val, '$' );
2011         if( i.bv_val == NULL ) return LDAP_INVALID_SYNTAX;
2012
2013         sn.bv_val = in->bv_val;
2014         sn.bv_len = i.bv_val - in->bv_val;
2015
2016         i.bv_val++;
2017         i.bv_len = in->bv_len - (sn.bv_len + 1);
2018
2019         /* validate serial number (strict for now) */
2020         for( n=0; n < sn.bv_len; n++ ) {
2021                 if( !ASCII_DIGIT(sn.bv_val[n]) ) {
2022                         return LDAP_INVALID_SYNTAX;
2023                 }
2024         }
2025
2026         /* validate DN */
2027         rc = dnValidate( NULL, &i );
2028         if( rc ) return LDAP_INVALID_SYNTAX;
2029
2030         return LDAP_SUCCESS;
2031 }
2032
2033 int
2034 serialNumberAndIssuerPretty(
2035         Syntax *syntax,
2036         struct berval *val,
2037         struct berval *out,
2038         void *ctx )
2039 {
2040         int rc;
2041         int state;
2042         ber_len_t n;
2043         struct berval sn, i, newi;
2044
2045         assert( val );
2046         assert( out );
2047
2048 #ifdef NEW_LOGGING
2049         LDAP_LOG( OPERATION, ARGS, ">>> serialNumberAndIssuerPretty: <%s>\n",
2050                 val->bv_val, 0, 0 );
2051 #else
2052         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
2053                 val->bv_val, 0, 0 );
2054 #endif
2055
2056         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2057
2058         i.bv_val = strchr( val->bv_val, '$' );
2059         if( i.bv_val == NULL ) return LDAP_INVALID_SYNTAX;
2060
2061         sn.bv_val = val->bv_val;
2062         sn.bv_len = i.bv_val - val->bv_val;
2063
2064         i.bv_val++;
2065         i.bv_len = val->bv_len - (sn.bv_len + 1);
2066
2067         /* eat leading zeros */
2068         for( n=0; n < (sn.bv_len-1); n++ ) {
2069                 if( sn.bv_val[n] != '0' ) break;
2070         }
2071         sn.bv_val += n;
2072         sn.bv_len -= n;
2073
2074         for( n=0; n < sn.bv_len; n++ ) {
2075                 if( !ASCII_DIGIT(sn.bv_val[n]) ) {
2076                         return LDAP_INVALID_SYNTAX;
2077                 }
2078         }
2079
2080         /* pretty DN */
2081         rc = dnPretty( syntax, &i, &newi, ctx );
2082         if( rc ) return LDAP_INVALID_SYNTAX;
2083
2084         /* make room from sn + "$" */
2085         out->bv_len = sn.bv_len + newi.bv_len + 1;
2086         out->bv_val = sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2087
2088         if( out->bv_val == NULL ) {
2089                 sl_free( newi.bv_val, ctx );
2090                 return LDAP_OTHER;
2091         }
2092
2093         /* push issuer over */
2094         AC_MEMCPY( &out->bv_val[sn.bv_len+1], newi.bv_val, newi.bv_len );
2095         /* insert sn and "$" */
2096         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2097         out->bv_val[sn.bv_len] = '$';
2098         /* terminate */
2099         out->bv_val[out->bv_len] = '\0';
2100
2101 #ifdef NEW_LOGGING
2102         LDAP_LOG( OPERATION, ARGS, "<<< serialNumberAndIssuerPretty: <%s>\n",
2103                 out->bv_val, 0, 0 );
2104 #else
2105         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
2106                 out->bv_val, 0, 0 );
2107 #endif
2108
2109         return LDAP_SUCCESS;
2110 }
2111
2112 /*
2113  * This routine is called by certificateExactNormalize when
2114  * certificateExactNormalize receives a search string instead of
2115  * a certificate. This routine checks if the search value is valid
2116  * and then returns the normalized value
2117  */
2118 static int
2119 serialNumberAndIssuerNormalize(
2120         slap_mask_t usage,
2121         Syntax *syntax,
2122         MatchingRule *mr,
2123         struct berval *val,
2124         struct berval *out,
2125         void *ctx )
2126 {
2127         int rc;
2128         int state;
2129         ber_len_t n;
2130         struct berval sn, i, newi;
2131
2132         assert( val );
2133         assert( out );
2134
2135 #ifdef NEW_LOGGING
2136         LDAP_LOG( OPERATION, ARGS, ">>> serialNumberAndIssuerNormalize: <%s>\n",
2137                 val->bv_val, 0, 0 );
2138 #else
2139         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
2140                 val->bv_val, 0, 0 );
2141 #endif
2142
2143         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2144
2145         i.bv_val = strchr( val->bv_val, '$' );
2146         if( i.bv_val == NULL ) return LDAP_INVALID_SYNTAX;
2147
2148         sn.bv_val = val->bv_val;
2149         sn.bv_len = i.bv_val - val->bv_val;
2150
2151         i.bv_val++;
2152         i.bv_len = val->bv_len - (sn.bv_len + 1);
2153
2154         /* eat leading zeros */
2155         for( n=0; n < (sn.bv_len-1); n++ ) {
2156                 if( sn.bv_val[n] != '0' ) break;
2157         }
2158         sn.bv_val += n;
2159         sn.bv_len -= n;
2160
2161         for( n=0; n < sn.bv_len; n++ ) {
2162                 if( !ASCII_DIGIT(sn.bv_val[n]) ) {
2163                         return LDAP_INVALID_SYNTAX;
2164                 }
2165         }
2166
2167         /* pretty DN */
2168         rc = dnNormalize( usage, syntax, mr, &i, &newi, ctx );
2169         if( rc ) return LDAP_INVALID_SYNTAX;
2170
2171         /* make room from sn + "$" */
2172         out->bv_len = sn.bv_len + newi.bv_len + 1;
2173         out->bv_val = sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2174
2175         if( out->bv_val == NULL ) {
2176                 sl_free( newi.bv_val, ctx );
2177                 return LDAP_OTHER;
2178         }
2179
2180         /* push issuer over */
2181         AC_MEMCPY( &out->bv_val[sn.bv_len+1], newi.bv_val, newi.bv_len );
2182         /* insert sn and "$" */
2183         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2184         out->bv_val[sn.bv_len] = '$';
2185         /* terminate */
2186         out->bv_val[out->bv_len] = '\0';
2187
2188 #ifdef NEW_LOGGING
2189         LDAP_LOG( OPERATION, ARGS, "<<< serialNumberAndIssuerNormalize: <%s>\n",
2190                 out->bv_val, 0, 0 );
2191 #else
2192         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
2193                 out->bv_val, 0, 0 );
2194 #endif
2195
2196         return rc;
2197 }
2198
2199 #ifdef HAVE_TLS
2200 static int
2201 certificateExactNormalize(
2202         slap_mask_t usage,
2203         Syntax *syntax,
2204         MatchingRule *mr,
2205         struct berval *val,
2206         struct berval *normalized,
2207         void *ctx )
2208 {
2209         int rc = LDAP_INVALID_SYNTAX;
2210         unsigned char *p;
2211         char *serial = NULL;
2212         ber_len_t seriallen;
2213         struct berval issuer_dn = { 0, NULL };
2214         X509_NAME *name = NULL;
2215         ASN1_INTEGER *sn = NULL;
2216         X509 *xcert = NULL;
2217
2218         if( val->bv_len == 0 ) goto done;
2219
2220         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
2221                 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
2222         }
2223
2224         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) );
2225
2226         p = (unsigned char *)val->bv_val;
2227         xcert = d2i_X509( NULL, &p, val->bv_len);
2228         if( xcert == NULL ) goto done;
2229
2230         sn=X509_get_serialNumber(xcert);
2231         if ( sn == NULL ) goto done;
2232         serial=i2s_ASN1_INTEGER(0, sn );
2233         if( serial == NULL ) goto done;
2234         seriallen=strlen(serial);
2235
2236         name=X509_get_issuer_name(xcert);
2237         if( name == NULL ) goto done;
2238         rc = dnX509normalize( name, &issuer_dn );
2239         if( rc != LDAP_SUCCESS ) goto done;
2240
2241         normalized->bv_len = seriallen + issuer_dn.bv_len + 1;
2242         normalized->bv_val = ch_malloc(normalized->bv_len+1);
2243         p = (unsigned char *)normalized->bv_val;
2244         AC_MEMCPY(p, serial, seriallen);
2245         p += seriallen;
2246         *p++ = '$';
2247         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
2248         p += issuer_dn.bv_len;
2249         *p = '\0';
2250
2251 #ifdef NEW_LOGGING
2252         LDAP_LOG( CONFIG, ARGS, "certificateExactNormalize: %s\n",
2253                 normalized->bv_val, 0, 0 );
2254 #else
2255         Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
2256                 normalized->bv_val, NULL, NULL );
2257 #endif
2258
2259 done:
2260         if (xcert) X509_free(xcert);
2261         if (serial) ch_free(serial);
2262         if (issuer_dn.bv_val) ber_memfree(issuer_dn.bv_val);
2263
2264         return rc;
2265 }
2266 #endif /* HAVE_TLS */
2267
2268
2269 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
2270 /* slight optimization - does not need the start parameter */
2271 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
2272 enum { start = 0 };
2273 #endif
2274
2275 static int
2276 check_time_syntax (struct berval *val,
2277         int start,
2278         int *parts,
2279         struct berval *fraction)
2280 {
2281         /*
2282          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
2283          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
2284          * GeneralizedTime supports leap seconds, UTCTime does not.
2285          */
2286         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
2287         static const int mdays[2][12] = {
2288                 /* non-leap years */
2289                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
2290                 /* leap years */
2291                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
2292         };
2293         char *p, *e;
2294         int part, c, c1, c2, tzoffset, leapyear = 0;
2295
2296         p = val->bv_val;
2297         e = p + val->bv_len;
2298
2299 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2300         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
2301 #endif
2302         for (part = start; part < 7 && p < e; part++) {
2303                 c1 = *p;
2304                 if (!ASCII_DIGIT(c1)) {
2305                         break;
2306                 }
2307                 p++;
2308                 if (p == e) {
2309                         return LDAP_INVALID_SYNTAX;
2310                 }
2311                 c = *p++;
2312                 if (!ASCII_DIGIT(c)) {
2313                         return LDAP_INVALID_SYNTAX;
2314                 }
2315                 c += c1 * 10 - '0' * 11;
2316                 if ((part | 1) == 3) {
2317                         --c;
2318                         if (c < 0) {
2319                                 return LDAP_INVALID_SYNTAX;
2320                         }
2321                 }
2322                 if (c >= ceiling[part]) {
2323                         if (! (c == 60 && part == 6 && start == 0))
2324                                 return LDAP_INVALID_SYNTAX;
2325                 }
2326                 parts[part] = c;
2327         }
2328         if (part < 5 + start) {
2329                 return LDAP_INVALID_SYNTAX;
2330         }
2331         for (; part < 9; part++) {
2332                 parts[part] = 0;
2333         }
2334
2335         /* leapyear check for the Gregorian calendar (year>1581) */
2336         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0)
2337         {
2338                 leapyear = 1;
2339         }
2340
2341         if (parts[3] >= mdays[leapyear][parts[2]]) {
2342                 return LDAP_INVALID_SYNTAX;
2343         }
2344
2345         if (start == 0) {
2346                 fraction->bv_val = p;
2347                 fraction->bv_len = 0;
2348                 if (p < e && (*p == '.' || *p == ',')) {
2349                         char *end_num;
2350                         while (++p < e && ASCII_DIGIT(*p))
2351                                 ;
2352                         if (p - fraction->bv_val == 1) {
2353                                 return LDAP_INVALID_SYNTAX;
2354                         }
2355                         for (end_num = p; end_num[-1] == '0'; --end_num)
2356                                 ;
2357                         c = end_num - fraction->bv_val;
2358                         if (c != 1)
2359                                 fraction->bv_len = c;
2360                 }
2361         }
2362
2363         if (p == e) {
2364                 /* no time zone */
2365                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2366         }
2367
2368         tzoffset = *p++;
2369         switch (tzoffset) {
2370         default:
2371                 return LDAP_INVALID_SYNTAX;
2372         case 'Z':
2373                 /* UTC */
2374                 break;
2375         case '+':
2376         case '-':
2377                 for (part = 7; part < 9 && p < e; part++) {
2378                         c1 = *p;
2379                         if (!ASCII_DIGIT(c1)) {
2380                                 break;
2381                         }
2382                         p++;
2383                         if (p == e) {
2384                                 return LDAP_INVALID_SYNTAX;
2385                         }
2386                         c2 = *p++;
2387                         if (!ASCII_DIGIT(c2)) {
2388                                 return LDAP_INVALID_SYNTAX;
2389                         }
2390                         parts[part] = c1 * 10 + c2 - '0' * 11;
2391                         if (parts[part] >= ceiling[part]) {
2392                                 return LDAP_INVALID_SYNTAX;
2393                         }
2394                 }
2395                 if (part < 8 + start) {
2396                         return LDAP_INVALID_SYNTAX;
2397                 }
2398
2399                 if (tzoffset == '-') {
2400                         /* negative offset to UTC, ie west of Greenwich */
2401                         parts[4] += parts[7];
2402                         parts[5] += parts[8];
2403                         /* offset is just hhmm, no seconds */
2404                         for (part = 6; --part >= 0; ) {
2405                                 if (part != 3) {
2406                                         c = ceiling[part];
2407                                 } else {
2408                                         c = mdays[leapyear][parts[2]];
2409                                 }
2410                                 if (parts[part] >= c) {
2411                                         if (part == 0) {
2412                                                 return LDAP_INVALID_SYNTAX;
2413                                         }
2414                                         parts[part] -= c;
2415                                         parts[part - 1]++;
2416                                         continue;
2417                                 } else if (part != 5) {
2418                                         break;
2419                                 }
2420                         }
2421                 } else {
2422                         /* positive offset to UTC, ie east of Greenwich */
2423                         parts[4] -= parts[7];
2424                         parts[5] -= parts[8];
2425                         for (part = 6; --part >= 0; ) {
2426                                 if (parts[part] < 0) {
2427                                         if (part == 0) {
2428                                                 return LDAP_INVALID_SYNTAX;
2429                                         }
2430                                         if (part != 3) {
2431                                                 c = ceiling[part];
2432                                         } else {
2433                                                 /* make first arg to % non-negative */
2434                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
2435                                         }
2436                                         parts[part] += c;
2437                                         parts[part - 1]--;
2438                                         continue;
2439                                 } else if (part != 5) {
2440                                         break;
2441                                 }
2442                         }
2443                 }
2444         }
2445
2446         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2447 }
2448
2449 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2450
2451 #if 0
2452 static int
2453 xutcTimeNormalize(
2454         Syntax *syntax,
2455         struct berval *val,
2456         struct berval *normalized )
2457 {
2458         int parts[9], rc;
2459
2460         rc = check_time_syntax(val, 1, parts, NULL);
2461         if (rc != LDAP_SUCCESS) {
2462                 return rc;
2463         }
2464
2465         normalized->bv_val = ch_malloc( 14 );
2466         if ( normalized->bv_val == NULL ) {
2467                 return LBER_ERROR_MEMORY;
2468         }
2469
2470         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
2471                 parts[1], parts[2] + 1, parts[3] + 1,
2472                 parts[4], parts[5], parts[6] );
2473         normalized->bv_len = 13;
2474
2475         return LDAP_SUCCESS;
2476 }
2477 #endif /* 0 */
2478
2479 static int
2480 utcTimeValidate(
2481         Syntax *syntax,
2482         struct berval *in )
2483 {
2484         int parts[9];
2485         return check_time_syntax(in, 1, parts, NULL);
2486 }
2487
2488 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
2489
2490 static int
2491 generalizedTimeValidate(
2492         Syntax *syntax,
2493         struct berval *in )
2494 {
2495         int parts[9];
2496         struct berval fraction;
2497         return check_time_syntax(in, 0, parts, &fraction);
2498 }
2499
2500 static int
2501 generalizedTimeNormalize(
2502         slap_mask_t usage,
2503         Syntax *syntax,
2504         MatchingRule *mr,
2505         struct berval *val,
2506         struct berval *normalized,
2507         void *ctx )
2508 {
2509         int parts[9], rc;
2510         unsigned int len;
2511         struct berval fraction;
2512
2513         rc = check_time_syntax(val, 0, parts, &fraction);
2514         if (rc != LDAP_SUCCESS) {
2515                 return rc;
2516         }
2517
2518         len = sizeof("YYYYmmddHHMMSSZ")-1 + fraction.bv_len;
2519         normalized->bv_val = sl_malloc( len + 1, ctx );
2520         if ( normalized->bv_val == NULL ) {
2521                 return LBER_ERROR_MEMORY;
2522         }
2523
2524         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
2525                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
2526                 parts[4], parts[5], parts[6] );
2527         if ( fraction.bv_len ) {
2528                 memcpy( normalized->bv_val + sizeof("YYYYmmddHHMMSSZ")-2,
2529                         fraction.bv_val, fraction.bv_len );
2530                 normalized->bv_val[sizeof("YYYYmmddHHMMSSZ")-2] = '.';
2531         }
2532         strcpy( normalized->bv_val + len-1, "Z" );
2533         normalized->bv_len = len;
2534
2535         return LDAP_SUCCESS;
2536 }
2537
2538 static int
2539 generalizedTimeOrderingMatch(
2540         int *matchp,
2541         slap_mask_t flags,
2542         Syntax *syntax,
2543         MatchingRule *mr,
2544         struct berval *value,
2545         void *assertedValue )
2546 {
2547         struct berval *asserted = (struct berval *) assertedValue;
2548         ber_len_t v_len  = value->bv_len;
2549         ber_len_t av_len = asserted->bv_len;
2550
2551         /* ignore trailing 'Z' when comparing */
2552         int match = memcmp( value->bv_val, asserted->bv_val,
2553                 (v_len < av_len ? v_len : av_len) - 1 );
2554         if ( match == 0 ) match = v_len - av_len;
2555
2556         *matchp = match;
2557         return LDAP_SUCCESS;
2558 }
2559
2560 static int
2561 nisNetgroupTripleValidate(
2562         Syntax *syntax,
2563         struct berval *val )
2564 {
2565         char *p, *e;
2566         int commas = 0;
2567
2568         if ( val->bv_len == 0 ) {
2569                 return LDAP_INVALID_SYNTAX;
2570         }
2571
2572         p = (char *)val->bv_val;
2573         e = p + val->bv_len;
2574
2575         if ( *p != '(' /*')'*/ ) {
2576                 return LDAP_INVALID_SYNTAX;
2577         }
2578
2579         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
2580                 if ( *p == ',' ) {
2581                         commas++;
2582                         if ( commas > 2 ) {
2583                                 return LDAP_INVALID_SYNTAX;
2584                         }
2585
2586                 } else if ( !AD_CHAR( *p ) ) {
2587                         return LDAP_INVALID_SYNTAX;
2588                 }
2589         }
2590
2591         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
2592                 return LDAP_INVALID_SYNTAX;
2593         }
2594
2595         p++;
2596
2597         if (p != e) {
2598                 return LDAP_INVALID_SYNTAX;
2599         }
2600
2601         return LDAP_SUCCESS;
2602 }
2603
2604 static int
2605 bootParameterValidate(
2606         Syntax *syntax,
2607         struct berval *val )
2608 {
2609         char *p, *e;
2610
2611         if ( val->bv_len == 0 ) {
2612                 return LDAP_INVALID_SYNTAX;
2613         }
2614
2615         p = (char *)val->bv_val;
2616         e = p + val->bv_len;
2617
2618         /* key */
2619         for (; ( p < e ) && ( *p != '=' ); p++ ) {
2620                 if ( !AD_CHAR( *p ) ) {
2621                         return LDAP_INVALID_SYNTAX;
2622                 }
2623         }
2624
2625         if ( *p != '=' ) {
2626                 return LDAP_INVALID_SYNTAX;
2627         }
2628
2629         /* server */
2630         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
2631                 if ( !AD_CHAR( *p ) ) {
2632                         return LDAP_INVALID_SYNTAX;
2633                 }
2634         }
2635
2636         if ( *p != ':' ) {
2637                 return LDAP_INVALID_SYNTAX;
2638         }
2639
2640         /* path */
2641         for ( p++; p < e; p++ ) {
2642                 if ( !SLAP_PRINTABLE( *p ) ) {
2643                         return LDAP_INVALID_SYNTAX;
2644                 }
2645         }
2646
2647         return LDAP_SUCCESS;
2648 }
2649
2650 static int
2651 firstComponentNormalize(
2652         slap_mask_t usage,
2653         Syntax *syntax,
2654         MatchingRule *mr,
2655         struct berval *val,
2656         struct berval *normalized,
2657         void *ctx )
2658 {
2659         int rc;
2660         struct berval oid;
2661         ber_len_t len;
2662
2663         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2664
2665         if( val->bv_val[0] != '(' /*')'*/ &&
2666                 val->bv_val[0] != '{' /*'}'*/ )
2667         {
2668                 return LDAP_INVALID_SYNTAX;
2669         }
2670
2671         /* trim leading white space */
2672         for( len=1;
2673                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
2674                 len++ )
2675         {
2676                 /* empty */
2677         }
2678
2679         /* grab next word */
2680         oid.bv_val = &val->bv_val[len];
2681         len = val->bv_len - len;
2682         for( oid.bv_len=0;
2683                 !ASCII_SPACE(oid.bv_val[oid.bv_len]) && oid.bv_len < len;
2684                 oid.bv_len++ )
2685         {
2686                 /* empty */
2687         }
2688
2689         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
2690                 rc = numericoidValidate( NULL, &oid );
2691         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
2692                 rc = integerValidate( NULL, &oid );
2693         } else {
2694                 rc = LDAP_INVALID_SYNTAX;
2695         }
2696         
2697
2698         if( rc == LDAP_SUCCESS ) {
2699                 ber_dupbv_x( normalized, &oid, ctx );
2700         }
2701
2702         return rc;
2703 }
2704
2705
2706 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
2707 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
2708
2709 static slap_syntax_defs_rec syntax_defs[] = {
2710         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
2711                 X_BINARY X_NOT_H_R ")",
2712                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL},
2713         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
2714                 0, NULL, NULL},
2715         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
2716                 0, NULL, NULL},
2717         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
2718                 X_NOT_H_R ")",
2719                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
2720         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
2721                 X_NOT_H_R ")",
2722                 SLAP_SYNTAX_BER, berValidate, NULL},
2723         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
2724                 0, bitStringValidate, NULL },
2725         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
2726                 0, booleanValidate, NULL},
2727         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
2728                 X_BINARY X_NOT_H_R ")",
2729                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, certificateValidate, NULL},
2730         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
2731                 X_BINARY X_NOT_H_R ")",
2732                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
2733         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
2734                 X_BINARY X_NOT_H_R ")",
2735                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
2736         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
2737                 0, countryStringValidate, NULL},
2738         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
2739                 0, dnValidate, dnPretty},
2740         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
2741                 0, NULL, NULL},
2742         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
2743                 0, NULL, NULL},
2744         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
2745                 0, UTF8StringValidate, NULL},
2746         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
2747                 0, NULL, NULL},
2748         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
2749                 0, NULL, NULL},
2750         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
2751                 0, NULL, NULL},
2752         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
2753                 0, NULL, NULL},
2754         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
2755                 0, NULL, NULL},
2756         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
2757                 0, printablesStringValidate, NULL},
2758         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
2759                 SLAP_SYNTAX_BLOB, NULL, NULL},
2760         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
2761                 0, generalizedTimeValidate, NULL},
2762         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
2763                 0, NULL, NULL},
2764         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
2765                 0, IA5StringValidate, NULL},
2766         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
2767                 0, integerValidate, NULL},
2768         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
2769                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
2770         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
2771                 0, NULL, NULL},
2772         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
2773                 0, NULL, NULL},
2774         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
2775                 0, NULL, NULL},
2776         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
2777                 0, NULL, NULL},
2778         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
2779                 0, NULL, NULL},
2780         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
2781                 0, nameUIDValidate, nameUIDPretty },
2782         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
2783                 0, NULL, NULL},
2784         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
2785                 0, numericStringValidate, NULL},
2786         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
2787                 0, NULL, NULL},
2788         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
2789                 0, numericoidValidate, NULL},
2790         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
2791                 0, IA5StringValidate, NULL},
2792         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
2793                 0, blobValidate, NULL},
2794         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
2795                 0, UTF8StringValidate, NULL},
2796         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
2797                 0, NULL, NULL},
2798         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
2799                 0, NULL, NULL},
2800         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
2801                 0, printableStringValidate, NULL},
2802         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
2803 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
2804                 0, subtreeSpecificationValidate, NULL},
2805         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
2806                 X_BINARY X_NOT_H_R ")",
2807                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
2808         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
2809                 0, printableStringValidate, NULL},
2810         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
2811                 0, NULL, NULL},
2812         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
2813                 0, printablesStringValidate, NULL},
2814 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2815         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
2816                 0, utcTimeValidate, NULL},
2817 #endif
2818         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
2819                 0, NULL, NULL},
2820         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
2821                 0, NULL, NULL},
2822         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
2823                 0, NULL, NULL},
2824         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
2825                 0, NULL, NULL},
2826         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
2827                 0, NULL, NULL},
2828
2829         /* RFC 2307 NIS Syntaxes */
2830         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
2831                 0, nisNetgroupTripleValidate, NULL},
2832         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
2833                 0, bootParameterValidate, NULL},
2834
2835         /* From PKIX *//* This OID is not published yet. */
2836         {"( 1.2.826.0.1.3344810.7.1 DESC 'Certificate Serial Number and Issuer' )",
2837                 SLAP_SYNTAX_HIDE,
2838                 serialNumberAndIssuerValidate,
2839                 serialNumberAndIssuerPretty},
2840
2841 #ifdef SLAPD_ACI_ENABLED
2842         /* OpenLDAP Experimental Syntaxes */
2843         {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
2844                 SLAP_SYNTAX_HIDE,
2845                 UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
2846                 NULL},
2847 #endif
2848
2849 #ifdef SLAPD_AUTHPASSWD
2850         /* needs updating */
2851         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
2852                 SLAP_SYNTAX_HIDE, NULL, NULL},
2853 #endif
2854
2855         {"( 1.3.6.1.4.1.4203.666.2.6 DESC 'UUID' )",
2856                 SLAP_SYNTAX_HIDE, UUIDValidate, NULL},
2857
2858         /* OpenLDAP Void Syntax */
2859         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
2860                 SLAP_SYNTAX_HIDE, inValidate, NULL},
2861         {NULL, 0, NULL, NULL}
2862 };
2863
2864 char *certificateExactMatchSyntaxes[] = {
2865         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
2866         NULL
2867 };
2868 char *directoryStringSyntaxes[] = {
2869         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
2870         NULL
2871 };
2872 char *integerFirstComponentMatchSyntaxes[] = {
2873         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
2874         "1.3.6.1.4.1.1466.115.121.1.17" /* ditStructureRuleDescription */,
2875         NULL
2876 };
2877 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
2878         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
2879         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
2880         "1.3.6.1.4.1.1466.115.121.1.16" /* ditContentRuleDescription */,
2881         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
2882         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
2883         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
2884         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
2885         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
2886         NULL
2887 };
2888
2889 /*
2890  * Other matching rules in X.520 that we do not use (yet):
2891  *
2892  * 2.5.13.9             numericStringOrderingMatch
2893  * 2.5.13.25    uTCTimeMatch
2894  * 2.5.13.26    uTCTimeOrderingMatch
2895  * 2.5.13.31    directoryStringFirstComponentMatch
2896  * 2.5.13.32    wordMatch
2897  * 2.5.13.33    keywordMatch
2898  * 2.5.13.36    certificatePairExactMatch
2899  * 2.5.13.37    certificatePairMatch
2900  * 2.5.13.38    certificateListExactMatch
2901  * 2.5.13.39    certificateListMatch
2902  * 2.5.13.40    algorithmIdentifierMatch
2903  * 2.5.13.41    storedPrefixMatch
2904  * 2.5.13.42    attributeCertificateMatch
2905  * 2.5.13.43    readerAndKeyIDMatch
2906  * 2.5.13.44    attributeIntegrityMatch
2907  */
2908 static slap_mrule_defs_rec mrule_defs[] = {
2909         /*
2910          * EQUALITY matching rules must be listed after associated APPROX
2911          * matching rules.  So, we list all APPROX matching rules first.
2912          */
2913         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
2914                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2915                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
2916                 NULL, NULL, directoryStringApproxMatch,
2917                 directoryStringApproxIndexer, directoryStringApproxFilter,
2918                 NULL},
2919
2920         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
2921                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
2922                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
2923                 NULL, NULL, IA5StringApproxMatch,
2924                 IA5StringApproxIndexer, IA5StringApproxFilter,
2925                 NULL},
2926
2927         /*
2928          * Other matching rules
2929          */
2930         
2931         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
2932                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
2933                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2934                 NULL, NULL, octetStringMatch,
2935                 octetStringIndexer, octetStringFilter,
2936                 NULL },
2937
2938         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
2939                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
2940                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2941                 NULL, dnNormalize, dnMatch,
2942                 octetStringIndexer, octetStringFilter,
2943                 NULL },
2944
2945         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
2946                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2947                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
2948                 NULL, UTF8StringNormalize, octetStringMatch,
2949                 octetStringIndexer, octetStringFilter,
2950                 directoryStringApproxMatchOID },
2951
2952         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
2953                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2954                 SLAP_MR_ORDERING, directoryStringSyntaxes,
2955                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
2956                 NULL, NULL,
2957                 "caseIgnoreMatch" },
2958
2959         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
2960                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2961                 SLAP_MR_SUBSTR, NULL,
2962                 NULL, UTF8StringNormalize, octetStringSubstringsMatch,
2963                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2964                 "caseIgnoreMatch" },
2965
2966         {"( 2.5.13.5 NAME 'caseExactMatch' "
2967                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2968                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
2969                 NULL, UTF8StringNormalize, octetStringMatch,
2970                 octetStringIndexer, octetStringFilter,
2971                 directoryStringApproxMatchOID },
2972
2973         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
2974                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2975                 SLAP_MR_ORDERING, directoryStringSyntaxes,
2976                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
2977                 NULL, NULL,
2978                 "caseExactMatch" },
2979
2980         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
2981                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2982                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
2983                 NULL, UTF8StringNormalize, octetStringSubstringsMatch,
2984                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2985                 "caseExactMatch" },
2986
2987         {"( 2.5.13.8 NAME 'numericStringMatch' "
2988                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
2989                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2990                 NULL, numericStringNormalize, octetStringSubstringsMatch,
2991                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2992                 NULL },
2993
2994         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
2995                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2996                 SLAP_MR_SUBSTR, NULL,
2997                 NULL, numericStringNormalize, octetStringSubstringsMatch,
2998                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2999                 "numericStringMatch" },
3000
3001         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
3002                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
3003                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3004                 NULL, NULL, NULL, NULL, NULL, NULL },
3005
3006         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
3007                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3008                 SLAP_MR_SUBSTR, NULL,
3009                 NULL, NULL, NULL, NULL, NULL,
3010                 "caseIgnoreListMatch" },
3011
3012         {"( 2.5.13.13 NAME 'booleanMatch' "
3013                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
3014                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3015                 NULL, NULL, booleanMatch,
3016                 octetStringIndexer, octetStringFilter,
3017                 NULL },
3018
3019         {"( 2.5.13.14 NAME 'integerMatch' "
3020                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3021                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3022                 NULL, NULL, integerMatch,
3023                 octetStringIndexer, octetStringFilter,
3024                 NULL },
3025
3026         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
3027                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3028                 SLAP_MR_ORDERING, NULL,
3029                 NULL, NULL, integerMatch,
3030                 NULL, NULL,
3031                 "integerMatch" },
3032
3033         {"( 2.5.13.16 NAME 'bitStringMatch' "
3034                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
3035                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3036                 NULL, NULL, octetStringMatch,
3037                 octetStringIndexer, octetStringFilter,
3038                 NULL },
3039
3040         {"( 2.5.13.17 NAME 'octetStringMatch' "
3041                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3042                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3043                 NULL, NULL, octetStringMatch,
3044                 octetStringIndexer, octetStringFilter,
3045                 NULL },
3046
3047         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
3048                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3049                 SLAP_MR_ORDERING, NULL,
3050                 NULL, NULL, octetStringOrderingMatch,
3051                 NULL, NULL,
3052                 "octetStringMatch" },
3053
3054         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
3055                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3056                 SLAP_MR_SUBSTR, NULL,
3057                 NULL, NULL, octetStringSubstringsMatch,
3058                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3059                 "octetStringMatch" },
3060
3061         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
3062                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
3063                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3064                 NULL,
3065                 telephoneNumberNormalize, octetStringMatch,
3066                 octetStringIndexer, octetStringFilter,
3067                 NULL },
3068
3069         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
3070                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3071                 SLAP_MR_SUBSTR, NULL,
3072                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
3073                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3074                 "telephoneNumberMatch" },
3075
3076         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
3077                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
3078                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3079                 NULL, NULL, NULL, NULL, NULL, NULL },
3080
3081         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
3082                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
3083                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3084                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
3085                 NULL, NULL,
3086                 NULL },
3087
3088         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
3089                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
3090                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3091                 NULL, NULL, NULL, NULL, NULL, NULL },
3092
3093         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
3094                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3095                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3096                 NULL, generalizedTimeNormalize, octetStringMatch,
3097                 NULL, NULL,
3098                 NULL },
3099
3100         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
3101                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3102                 SLAP_MR_ORDERING, NULL,
3103                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
3104                 NULL, NULL,
3105                 "generalizedTimeMatch" },
3106
3107         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
3108                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3109                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3110                         integerFirstComponentMatchSyntaxes,
3111                 NULL, firstComponentNormalize, integerMatch,
3112                 octetStringIndexer, octetStringFilter,
3113                 NULL },
3114
3115         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
3116                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3117                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3118                         objectIdentifierFirstComponentMatchSyntaxes,
3119                 NULL, firstComponentNormalize, octetStringMatch,
3120                 octetStringIndexer, octetStringFilter,
3121                 NULL },
3122
3123         {"( 2.5.13.34 NAME 'certificateExactMatch' "
3124                 "SYNTAX 1.2.826.0.1.3344810.7.1 )",
3125                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
3126 #ifdef HAVE_TLS
3127                 NULL, certificateExactNormalize, octetStringMatch,
3128                 octetStringIndexer, octetStringFilter,
3129 #else
3130                 NULL, NULL, NULL, NULL, NULL,
3131 #endif
3132                 NULL },
3133
3134         {"( 2.5.13.35 NAME 'certificateMatch' "
3135                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )",
3136                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3137 #ifdef HAVE_TLS
3138                 NULL, NULL, octetStringMatch,
3139                 octetStringIndexer, octetStringFilter,
3140 #else
3141                 NULL, NULL, NULL, NULL, NULL,
3142 #endif
3143                 NULL },
3144
3145         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
3146                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3147                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3148                 NULL, IA5StringNormalize, octetStringMatch,
3149                 octetStringIndexer, octetStringFilter,
3150                 IA5StringApproxMatchOID },
3151
3152         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
3153                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3154                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3155                 NULL, IA5StringNormalize, octetStringMatch,
3156                 octetStringIndexer, octetStringFilter,
3157                 IA5StringApproxMatchOID },
3158
3159         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
3160                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3161                 SLAP_MR_SUBSTR, NULL,
3162                 NULL, IA5StringNormalize, octetStringSubstringsMatch,
3163                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3164                 "caseIgnoreIA5Match" },
3165
3166         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
3167                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3168                 SLAP_MR_SUBSTR, NULL,
3169                 NULL, IA5StringNormalize, octetStringSubstringsMatch,
3170                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3171                 "caseExactIA5Match" },
3172
3173 #ifdef SLAPD_AUTHPASSWD
3174         /* needs updating */
3175         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
3176                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3177                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3178                 NULL, NULL, authPasswordMatch,
3179                 NULL, NULL,
3180                 NULL},
3181 #endif
3182
3183 #ifdef SLAPD_ACI_ENABLED
3184         {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
3185                 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
3186                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3187                 NULL, NULL, OpenLDAPaciMatch,
3188                 NULL, NULL,
3189                 NULL},
3190 #endif
3191
3192         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
3193                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3194                 SLAP_MR_EXT, NULL,
3195                 NULL, NULL, integerBitAndMatch,
3196                 NULL, NULL,
3197                 "integerMatch" },
3198
3199         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
3200                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3201                 SLAP_MR_EXT, NULL,
3202                 NULL, NULL, integerBitOrMatch,
3203                 NULL, NULL,
3204                 "integerMatch" },
3205
3206         {"( 1.3.6.1.4.1.4203.666.4.6 NAME 'UUIDMatch' "
3207                 "SYNTAX 1.3.6.1.4.1.4203.666.2.6 )",
3208                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3209                 NULL, UUIDNormalize, octetStringMatch,
3210                 octetStringIndexer, octetStringFilter,
3211                 NULL},
3212
3213         {"( 1.3.6.1.4.1.4203.666.4.7 NAME 'UUIDOrderingMatch' "
3214                 "SYNTAX 1.3.6.1.4.1.4203.666.2.6 )",
3215                 SLAP_MR_HIDE | SLAP_MR_ORDERING, NULL,
3216                 NULL, UUIDNormalize, octetStringOrderingMatch,
3217                 octetStringIndexer, octetStringFilter,
3218                 "UUIDMatch"},
3219
3220         {NULL, SLAP_MR_NONE, NULL,
3221                 NULL, NULL, NULL, NULL, NULL,
3222                 NULL }
3223 };
3224
3225 int
3226 slap_schema_init( void )
3227 {
3228         int             res;
3229         int             i;
3230
3231         /* we should only be called once (from main) */
3232         assert( schema_init_done == 0 );
3233
3234         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
3235                 res = register_syntax( &syntax_defs[i] );
3236
3237                 if ( res ) {
3238                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
3239                                  syntax_defs[i].sd_desc );
3240                         return LDAP_OTHER;
3241                 }
3242         }
3243
3244         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
3245                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
3246                         mrule_defs[i].mrd_compat_syntaxes == NULL )
3247                 {
3248                         fprintf( stderr,
3249                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
3250                                  mrule_defs[i].mrd_desc );
3251                         continue;
3252                 }
3253
3254                 res = register_matching_rule( &mrule_defs[i] );
3255
3256                 if ( res ) {
3257                         fprintf( stderr,
3258                                 "slap_schema_init: Error registering matching rule %s\n",
3259                                  mrule_defs[i].mrd_desc );
3260                         return LDAP_OTHER;
3261                 }
3262         }
3263
3264         res = slap_schema_load();
3265         schema_init_done = 1;
3266         return res;
3267 }
3268
3269 void
3270 schema_destroy( void )
3271 {
3272         oidm_destroy();
3273         oc_destroy();
3274         at_destroy();
3275         mr_destroy();
3276         mru_destroy();
3277         syn_destroy();
3278 }