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