]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
4f4edc6c353bda6baba27dcab305bf161180f2b6
[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         /* trim leading spaces? */
1327         wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1328                 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1329
1330         for( i = 0; i < tmp.bv_len; i++) {
1331                 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1332                         if( wasspace++ == 0 ) {
1333                                 /* trim repeated spaces */
1334                                 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1335                         }
1336                 } else {
1337                         wasspace = 0;
1338                         nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1339                 }
1340         }
1341
1342         if( !BER_BVISEMPTY( &nvalue ) ) {
1343                 /* trim trailing space? */
1344                 if( wasspace && (
1345                         (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1346                         ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1347                 {
1348                         --nvalue.bv_len;
1349                 }
1350                 nvalue.bv_val[nvalue.bv_len] = '\0';
1351
1352         } else {
1353                 /* string of all spaces is treated as one space */
1354                 nvalue.bv_val[0] = ' ';
1355                 nvalue.bv_val[1] = '\0';
1356                 nvalue.bv_len = 1;
1357         }
1358
1359         *normalized = nvalue;
1360         return LDAP_SUCCESS;
1361 }
1362
1363 static int
1364 directoryStringSubstringsMatch(
1365         int *matchp,
1366         slap_mask_t flags,
1367         Syntax *syntax,
1368         MatchingRule *mr,
1369         struct berval *value,
1370         void *assertedValue )
1371 {
1372         int match = 0;
1373         SubstringsAssertion *sub = assertedValue;
1374         struct berval left = *value;
1375         int i;
1376         int priorspace=0;
1377
1378         if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1379                 if ( sub->sa_initial.bv_len > left.bv_len ) {
1380                         /* not enough left */
1381                         match = 1;
1382                         goto done;
1383                 }
1384
1385                 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1386                         sub->sa_initial.bv_len );
1387
1388                 if ( match != 0 ) {
1389                         goto done;
1390                 }
1391
1392                 left.bv_val += sub->sa_initial.bv_len;
1393                 left.bv_len -= sub->sa_initial.bv_len;
1394
1395                 priorspace = ASCII_SPACE(
1396                         sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1397         }
1398
1399         if ( sub->sa_any ) {
1400                 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1401                         ber_len_t idx;
1402                         char *p;
1403
1404                         if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] ) 
1405                                 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1406                         { 
1407                                 /* allow next space to match */
1408                                 left.bv_val--;
1409                                 left.bv_len++;
1410                         }
1411                         priorspace=0;
1412
1413 retry:
1414                         if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1415                                 continue;
1416                         }
1417
1418                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1419                                 /* not enough left */
1420                                 match = 1;
1421                                 goto done;
1422                         }
1423
1424                         p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1425
1426                         if( p == NULL ) {
1427                                 match = 1;
1428                                 goto done;
1429                         }
1430
1431                         idx = p - left.bv_val;
1432
1433                         if ( idx >= left.bv_len ) {
1434                                 /* this shouldn't happen */
1435                                 return LDAP_OTHER;
1436                         }
1437
1438                         left.bv_val = p;
1439                         left.bv_len -= idx;
1440
1441                         if ( sub->sa_any[i].bv_len > left.bv_len ) {
1442                                 /* not enough left */
1443                                 match = 1;
1444                                 goto done;
1445                         }
1446
1447                         match = memcmp( left.bv_val,
1448                                 sub->sa_any[i].bv_val,
1449                                 sub->sa_any[i].bv_len );
1450
1451                         if ( match != 0 ) {
1452                                 left.bv_val++;
1453                                 left.bv_len--;
1454                                 goto retry;
1455                         }
1456
1457                         left.bv_val += sub->sa_any[i].bv_len;
1458                         left.bv_len -= sub->sa_any[i].bv_len;
1459
1460                         priorspace = ASCII_SPACE(
1461                                 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1462                 }
1463         }
1464
1465         if ( !BER_BVISNULL( &sub->sa_final ) ) {
1466                 if( priorspace && !BER_BVISEMPTY( &sub->sa_final ) 
1467                         && ASCII_SPACE( sub->sa_final.bv_val[0] ))
1468                 { 
1469                         /* allow next space to match */
1470                         left.bv_val--;
1471                         left.bv_len++;
1472                 }
1473
1474                 if ( sub->sa_final.bv_len > left.bv_len ) {
1475                         /* not enough left */
1476                         match = 1;
1477                         goto done;
1478                 }
1479
1480                 match = memcmp( sub->sa_final.bv_val,
1481                         &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1482                         sub->sa_final.bv_len );
1483
1484                 if ( match != 0 ) {
1485                         goto done;
1486                 }
1487         }
1488
1489 done:
1490         *matchp = match;
1491         return LDAP_SUCCESS;
1492 }
1493
1494 #if defined(SLAPD_APPROX_INITIALS)
1495 #       define SLAPD_APPROX_DELIMITER "._ "
1496 #       define SLAPD_APPROX_WORDLEN 2
1497 #else
1498 #       define SLAPD_APPROX_DELIMITER " "
1499 #       define SLAPD_APPROX_WORDLEN 1
1500 #endif
1501
1502 static int
1503 approxMatch(
1504         int *matchp,
1505         slap_mask_t flags,
1506         Syntax *syntax,
1507         MatchingRule *mr,
1508         struct berval *value,
1509         void *assertedValue )
1510 {
1511         struct berval *nval, *assertv;
1512         char *val, **values, **words, *c;
1513         int i, count, len, nextchunk=0, nextavail=0;
1514
1515         /* Yes, this is necessary */
1516         nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
1517         if( nval == NULL ) {
1518                 *matchp = 1;
1519                 return LDAP_SUCCESS;
1520         }
1521
1522         /* Yes, this is necessary */
1523         assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1524                 NULL, LDAP_UTF8_APPROX, NULL );
1525         if( assertv == NULL ) {
1526                 ber_bvfree( nval );
1527                 *matchp = 1;
1528                 return LDAP_SUCCESS;
1529         }
1530
1531         /* Isolate how many words there are */
1532         for ( c = nval->bv_val, count = 1; *c; c++ ) {
1533                 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1534                 if ( c == NULL ) break;
1535                 *c = '\0';
1536                 count++;
1537         }
1538
1539         /* Get a phonetic copy of each word */
1540         words = (char **)ch_malloc( count * sizeof(char *) );
1541         values = (char **)ch_malloc( count * sizeof(char *) );
1542         for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
1543                 words[i] = c;
1544                 values[i] = phonetic(c);
1545         }
1546
1547         /* Work through the asserted value's words, to see if at least some
1548            of the words are there, in the same order. */
1549         len = 0;
1550         while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1551                 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1552                 if( len == 0 ) {
1553                         nextchunk++;
1554                         continue;
1555                 }
1556 #if defined(SLAPD_APPROX_INITIALS)
1557                 else if( len == 1 ) {
1558                         /* Single letter words need to at least match one word's initial */
1559                         for( i=nextavail; i<count; i++ )
1560                                 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1561                                         nextavail=i+1;
1562                                         break;
1563                                 }
1564                 }
1565 #endif
1566                 else {
1567                         /* Isolate the next word in the asserted value and phonetic it */
1568                         assertv->bv_val[nextchunk+len] = '\0';
1569                         val = phonetic( assertv->bv_val + nextchunk );
1570
1571                         /* See if this phonetic chunk is in the remaining words of *value */
1572                         for( i=nextavail; i<count; i++ ){
1573                                 if( !strcmp( val, values[i] ) ){
1574                                         nextavail = i+1;
1575                                         break;
1576                                 }
1577                         }
1578                         ch_free( val );
1579                 }
1580
1581                 /* This chunk in the asserted value was NOT within the *value. */
1582                 if( i >= count ) {
1583                         nextavail=-1;
1584                         break;
1585                 }
1586
1587                 /* Go on to the next word in the asserted value */
1588                 nextchunk += len+1;
1589         }
1590
1591         /* If some of the words were seen, call it a match */
1592         if( nextavail > 0 ) {
1593                 *matchp = 0;
1594         }
1595         else {
1596                 *matchp = 1;
1597         }
1598
1599         /* Cleanup allocs */
1600         ber_bvfree( assertv );
1601         for( i=0; i<count; i++ ) {
1602                 ch_free( values[i] );
1603         }
1604         ch_free( values );
1605         ch_free( words );
1606         ber_bvfree( nval );
1607
1608         return LDAP_SUCCESS;
1609 }
1610
1611 static int 
1612 approxIndexer(
1613         slap_mask_t use,
1614         slap_mask_t flags,
1615         Syntax *syntax,
1616         MatchingRule *mr,
1617         struct berval *prefix,
1618         BerVarray values,
1619         BerVarray *keysp,
1620         void *ctx )
1621 {
1622         char *c;
1623         int i,j, len, wordcount, keycount=0;
1624         struct berval *newkeys;
1625         BerVarray keys=NULL;
1626
1627         for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
1628                 struct berval val = BER_BVNULL;
1629                 /* Yes, this is necessary */
1630                 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
1631                 assert( !BER_BVISNULL( &val ) );
1632
1633                 /* Isolate how many words there are. There will be a key for each */
1634                 for( wordcount = 0, c = val.bv_val; *c; c++) {
1635                         len = strcspn(c, SLAPD_APPROX_DELIMITER);
1636                         if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1637                         c+= len;
1638                         if (*c == '\0') break;
1639                         *c = '\0';
1640                 }
1641
1642                 /* Allocate/increase storage to account for new keys */
1643                 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
1644                         * sizeof(struct berval) );
1645                 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1646                 if( keys ) ch_free( keys );
1647                 keys = newkeys;
1648
1649                 /* Get a phonetic copy of each word */
1650                 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1651                         len = strlen( c );
1652                         if( len < SLAPD_APPROX_WORDLEN ) continue;
1653                         ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1654                         keycount++;
1655                         i++;
1656                 }
1657
1658                 ber_memfree( val.bv_val );
1659         }
1660         BER_BVZERO( &keys[keycount] );
1661         *keysp = keys;
1662
1663         return LDAP_SUCCESS;
1664 }
1665
1666 static int 
1667 approxFilter(
1668         slap_mask_t use,
1669         slap_mask_t flags,
1670         Syntax *syntax,
1671         MatchingRule *mr,
1672         struct berval *prefix,
1673         void * assertedValue,
1674         BerVarray *keysp,
1675         void *ctx )
1676 {
1677         char *c;
1678         int i, count, len;
1679         struct berval *val;
1680         BerVarray keys;
1681
1682         /* Yes, this is necessary */
1683         val = UTF8bvnormalize( ((struct berval *)assertedValue),
1684                 NULL, LDAP_UTF8_APPROX, NULL );
1685         if( val == NULL || BER_BVISNULL( val ) ) {
1686                 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1687                 BER_BVZERO( &keys[0] );
1688                 *keysp = keys;
1689                 ber_bvfree( val );
1690                 return LDAP_SUCCESS;
1691         }
1692
1693         /* Isolate how many words there are. There will be a key for each */
1694         for( count = 0,c = val->bv_val; *c; c++) {
1695                 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1696                 if( len >= SLAPD_APPROX_WORDLEN ) count++;
1697                 c+= len;
1698                 if (*c == '\0') break;
1699                 *c = '\0';
1700         }
1701
1702         /* Allocate storage for new keys */
1703         keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1704
1705         /* Get a phonetic copy of each word */
1706         for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1707                 len = strlen(c);
1708                 if( len < SLAPD_APPROX_WORDLEN ) continue;
1709                 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1710                 i++;
1711         }
1712
1713         ber_bvfree( val );
1714
1715         BER_BVZERO( &keys[count] );
1716         *keysp = keys;
1717
1718         return LDAP_SUCCESS;
1719 }
1720
1721 /* Remove all spaces and '-' characters */
1722 static int
1723 telephoneNumberNormalize(
1724         slap_mask_t usage,
1725         Syntax *syntax,
1726         MatchingRule *mr,
1727         struct berval *val,
1728         struct berval *normalized,
1729         void *ctx )
1730 {
1731         char *p, *q;
1732
1733         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ));
1734
1735         /* validator should have refused an empty string */
1736         assert( !BER_BVISEMPTY( val ) );
1737
1738         q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
1739
1740         for( p = val->bv_val; *p; p++ ) {
1741                 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1742                         *q++ = *p;
1743                 }
1744         }
1745         *q = '\0';
1746
1747         normalized->bv_len = q - normalized->bv_val;
1748
1749         if( BER_BVISEMPTY( normalized ) ) {
1750                 slap_sl_free( normalized->bv_val, ctx );
1751                 BER_BVZERO( normalized );
1752                 return LDAP_INVALID_SYNTAX;
1753         }
1754
1755         return LDAP_SUCCESS;
1756 }
1757
1758 static int
1759 numericoidValidate(
1760         Syntax *syntax,
1761         struct berval *in )
1762 {
1763         struct berval val = *in;
1764
1765         if( BER_BVISEMPTY( &val ) ) {
1766                 /* disallow empty strings */
1767                 return LDAP_INVALID_SYNTAX;
1768         }
1769
1770         while( OID_LEADCHAR( val.bv_val[0] ) ) {
1771                 if ( val.bv_len == 1 ) {
1772                         return LDAP_SUCCESS;
1773                 }
1774
1775                 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
1776                         break;
1777                 }
1778
1779                 val.bv_val++;
1780                 val.bv_len--;
1781
1782                 while ( OID_LEADCHAR( val.bv_val[0] )) {
1783                         val.bv_val++;
1784                         val.bv_len--;
1785
1786                         if ( val.bv_len == 0 ) {
1787                                 return LDAP_SUCCESS;
1788                         }
1789                 }
1790
1791                 if( !OID_SEPARATOR( val.bv_val[0] )) {
1792                         break;
1793                 }
1794
1795                 val.bv_val++;
1796                 val.bv_len--;
1797         }
1798
1799         return LDAP_INVALID_SYNTAX;
1800 }
1801
1802 static int
1803 integerValidate(
1804         Syntax *syntax,
1805         struct berval *in )
1806 {
1807         ber_len_t i;
1808         struct berval val = *in;
1809
1810         if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
1811
1812         if ( val.bv_val[0] == '-' ) {
1813                 val.bv_len--;
1814                 val.bv_val++;
1815
1816                 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
1817                         return LDAP_INVALID_SYNTAX;
1818                 }
1819
1820                 if( val.bv_val[0] == '0' ) { /* "-0" */
1821                         return LDAP_INVALID_SYNTAX;
1822                 }
1823
1824         } else if ( val.bv_val[0] == '0' ) {
1825                 if( val.bv_len > 1 ) { /* "0<more>" */
1826                         return LDAP_INVALID_SYNTAX;
1827                 }
1828
1829                 return LDAP_SUCCESS;
1830         }
1831
1832         for( i=0; i < val.bv_len; i++ ) {
1833                 if( !ASCII_DIGIT(val.bv_val[i]) ) {
1834                         return LDAP_INVALID_SYNTAX;
1835                 }
1836         }
1837
1838         return LDAP_SUCCESS;
1839 }
1840
1841 static int
1842 integerMatch(
1843         int *matchp,
1844         slap_mask_t flags,
1845         Syntax *syntax,
1846         MatchingRule *mr,
1847         struct berval *value,
1848         void *assertedValue )
1849 {
1850         struct berval *asserted = (struct berval *) assertedValue;
1851         int vsign = 1, asign = 1;       /* default sign = '+' */
1852         struct berval v, a;
1853         int match;
1854
1855         v = *value;
1856         if( v.bv_val[0] == '-' ) {
1857                 vsign = -1;
1858                 v.bv_val++;
1859                 v.bv_len--;
1860         }
1861
1862         if( BER_BVISEMPTY( &v ) ) vsign = 0;
1863
1864         a = *asserted;
1865         if( a.bv_val[0] == '-' ) {
1866                 asign = -1;
1867                 a.bv_val++;
1868                 a.bv_len--;
1869         }
1870
1871         if( BER_BVISEMPTY( &a ) ) vsign = 0;
1872
1873         match = vsign - asign;
1874         if( match == 0 ) {
1875                 match = ( v.bv_len != a.bv_len
1876                         ? ( v.bv_len < a.bv_len ? -1 : 1 )
1877                         : memcmp( v.bv_val, a.bv_val, v.bv_len ));
1878                 if( vsign < 0 ) match = -match;
1879         }
1880
1881         *matchp = match;
1882         return LDAP_SUCCESS;
1883 }
1884         
1885 static int
1886 countryStringValidate(
1887         Syntax *syntax,
1888         struct berval *val )
1889 {
1890         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
1891
1892         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
1893                 return LDAP_INVALID_SYNTAX;
1894         }
1895         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
1896                 return LDAP_INVALID_SYNTAX;
1897         }
1898
1899         return LDAP_SUCCESS;
1900 }
1901
1902 static int
1903 printableStringValidate(
1904         Syntax *syntax,
1905         struct berval *val )
1906 {
1907         ber_len_t i;
1908
1909         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
1910
1911         for(i=0; i < val->bv_len; i++) {
1912                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
1913                         return LDAP_INVALID_SYNTAX;
1914                 }
1915         }
1916
1917         return LDAP_SUCCESS;
1918 }
1919
1920 static int
1921 printablesStringValidate(
1922         Syntax *syntax,
1923         struct berval *val )
1924 {
1925         ber_len_t i, len;
1926
1927         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
1928
1929         for(i=0,len=0; i < val->bv_len; i++) {
1930                 int c = val->bv_val[i];
1931
1932                 if( c == '$' ) {
1933                         if( len == 0 ) {
1934                                 return LDAP_INVALID_SYNTAX;
1935                         }
1936                         len = 0;
1937
1938                 } else if ( SLAP_PRINTABLE(c) ) {
1939                         len++;
1940                 } else {
1941                         return LDAP_INVALID_SYNTAX;
1942                 }
1943         }
1944
1945         if( len == 0 ) {
1946                 return LDAP_INVALID_SYNTAX;
1947         }
1948
1949         return LDAP_SUCCESS;
1950 }
1951
1952 static int
1953 IA5StringValidate(
1954         Syntax *syntax,
1955         struct berval *val )
1956 {
1957         ber_len_t i;
1958
1959         if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
1960
1961         for(i=0; i < val->bv_len; i++) {
1962                 if( !LDAP_ASCII(val->bv_val[i]) ) {
1963                         return LDAP_INVALID_SYNTAX;
1964                 }
1965         }
1966
1967         return LDAP_SUCCESS;
1968 }
1969
1970 static int
1971 IA5StringNormalize(
1972         slap_mask_t use,
1973         Syntax *syntax,
1974         MatchingRule *mr,
1975         struct berval *val,
1976         struct berval *normalized,
1977         void *ctx )
1978 {
1979         char *p, *q;
1980         int casefold = !SLAP_MR_ASSOCIATED(mr, slap_schema.si_mr_caseExactIA5Match);
1981
1982         assert( !BER_BVISEMPTY( val ) );
1983
1984         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
1985
1986         p = val->bv_val;
1987
1988         /* Ignore initial whitespace */
1989         while ( ASCII_SPACE( *p ) ) p++;
1990
1991         normalized->bv_val = ber_strdup_x( p, ctx );
1992         p = q = normalized->bv_val;
1993
1994         while ( *p ) {
1995                 if ( ASCII_SPACE( *p ) ) {
1996                         *q++ = *p++;
1997
1998                         /* Ignore the extra whitespace */
1999                         while ( ASCII_SPACE( *p ) ) {
2000                                 p++;
2001                         }
2002
2003                 } else if ( casefold ) {
2004                         /* Most IA5 rules require casefolding */
2005                         *q++ = TOLOWER(*p); p++;
2006
2007                 } else {
2008                         *q++ = *p++;
2009                 }
2010         }
2011
2012         assert( normalized->bv_val <= p );
2013         assert( q <= p );
2014
2015         /*
2016          * If the string ended in space, backup the pointer one
2017          * position.  One is enough because the above loop collapsed
2018          * all whitespace to a single space.
2019          */
2020         if ( ASCII_SPACE( q[-1] ) ) --q;
2021
2022         /* null terminate */
2023         *q = '\0';
2024
2025         normalized->bv_len = q - normalized->bv_val;
2026         if( BER_BVISEMPTY( normalized ) ) {
2027                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2028                 normalized->bv_val[0] = ' ';
2029                 normalized->bv_val[1] = '\0';
2030                 normalized->bv_len = 1;
2031         }
2032
2033         return LDAP_SUCCESS;
2034 }
2035
2036 static int
2037 UUIDValidate(
2038         Syntax *syntax,
2039         struct berval *in )
2040 {
2041         int i;
2042         if( in->bv_len != 36 ) {
2043                 return LDAP_INVALID_SYNTAX;
2044         }
2045
2046         for( i=0; i<36; i++ ) {
2047                 switch(i) {
2048                         case 8:
2049                         case 13:
2050                         case 18:
2051                         case 23:
2052                                 if( in->bv_val[i] != '-' ) {
2053                                         return LDAP_INVALID_SYNTAX;
2054                                 }
2055                                 break;
2056                         default:
2057                                 if( !ASCII_HEX( in->bv_val[i]) ) {
2058                                         return LDAP_INVALID_SYNTAX;
2059                                 }
2060                 }
2061         }
2062         
2063         return LDAP_SUCCESS;
2064 }
2065
2066 static int
2067 UUIDNormalize(
2068         slap_mask_t usage,
2069         Syntax *syntax,
2070         MatchingRule *mr,
2071         struct berval *val,
2072         struct berval *normalized,
2073         void *ctx )
2074 {
2075         unsigned char octet = '\0';
2076         int i;
2077         int j;
2078         normalized->bv_len = 16;
2079         normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2080
2081         for( i=0, j=0; i<36; i++ ) {
2082                 unsigned char nibble;
2083                 if( val->bv_val[i] == '-' ) {
2084                         continue;
2085
2086                 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2087                         nibble = val->bv_val[i] - '0';
2088
2089                 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2090                         nibble = val->bv_val[i] - ('a'-10);
2091
2092                 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2093                         nibble = val->bv_val[i] - ('A'-10);
2094
2095                 } else {
2096                         slap_sl_free( normalized->bv_val, ctx );
2097                         return LDAP_INVALID_SYNTAX;
2098                 }
2099
2100                 if( j & 1 ) {
2101                         octet |= nibble;
2102                         normalized->bv_val[j>>1] = octet;
2103                 } else {
2104                         octet = nibble << 4;
2105                 }
2106                 j++;
2107         }
2108
2109         normalized->bv_val[normalized->bv_len] = 0;
2110         return LDAP_SUCCESS;
2111 }
2112
2113
2114
2115 static int
2116 numericStringValidate(
2117         Syntax *syntax,
2118         struct berval *in )
2119 {
2120         ber_len_t i;
2121
2122         if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2123
2124         for(i=0; i < in->bv_len; i++) {
2125                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2126                         return LDAP_INVALID_SYNTAX;
2127                 }
2128         }
2129
2130         return LDAP_SUCCESS;
2131 }
2132
2133 static int
2134 numericStringNormalize(
2135         slap_mask_t usage,
2136         Syntax *syntax,
2137         MatchingRule *mr,
2138         struct berval *val,
2139         struct berval *normalized,
2140         void *ctx )
2141 {
2142         /* removal all spaces */
2143         char *p, *q;
2144
2145         assert( !BER_BVISEMPTY( val ) );
2146
2147         normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2148
2149         p = val->bv_val;
2150         q = normalized->bv_val;
2151
2152         while ( *p ) {
2153                 if ( ASCII_SPACE( *p ) ) {
2154                         /* Ignore whitespace */
2155                         p++;
2156                 } else {
2157                         *q++ = *p++;
2158                 }
2159         }
2160
2161         /* we should have copied no more then is in val */
2162         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2163
2164         /* null terminate */
2165         *q = '\0';
2166
2167         normalized->bv_len = q - normalized->bv_val;
2168
2169         if( BER_BVISEMPTY( normalized ) ) {
2170                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2171                 normalized->bv_val[0] = ' ';
2172                 normalized->bv_val[1] = '\0';
2173                 normalized->bv_len = 1;
2174         }
2175
2176         return LDAP_SUCCESS;
2177 }
2178
2179 /*
2180  * Integer conversion macros that will use the largest available
2181  * type.
2182  */
2183 #if defined(HAVE_STRTOLL) && defined(LLONG_MAX) \
2184         && defined(LLONG_MIN) && defined(HAVE_LONG_LONG)
2185 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
2186 # define SLAP_LONG_MAX       LLONG_MAX
2187 # define SLAP_LONG_MIN       LLONG_MIN
2188 # define SLAP_LONG           long long
2189 #else
2190 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
2191 # define SLAP_LONG_MAX       LONG_MAX
2192 # define SLAP_LONG_MIN       LONG_MIN
2193 # define SLAP_LONG           long
2194 #endif /* HAVE_STRTOLL ... */
2195
2196 static int
2197 integerBitAndMatch(
2198         int *matchp,
2199         slap_mask_t flags,
2200         Syntax *syntax,
2201         MatchingRule *mr,
2202         struct berval *value,
2203         void *assertedValue )
2204 {
2205         SLAP_LONG lValue, lAssertedValue;
2206
2207         /* safe to assume integers are NUL terminated? */
2208         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2209         if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX) &&
2210                 errno == ERANGE )
2211         {
2212                 return LDAP_CONSTRAINT_VIOLATION;
2213         }
2214
2215         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2216                 NULL, 10);
2217         if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX ) &&
2218                 errno == ERANGE )
2219         {
2220                 return LDAP_CONSTRAINT_VIOLATION;
2221         }
2222
2223         *matchp = (lValue & lAssertedValue) ? 0 : 1;
2224         return LDAP_SUCCESS;
2225 }
2226
2227 static int
2228 integerBitOrMatch(
2229         int *matchp,
2230         slap_mask_t flags,
2231         Syntax *syntax,
2232         MatchingRule *mr,
2233         struct berval *value,
2234         void *assertedValue )
2235 {
2236         SLAP_LONG lValue, lAssertedValue;
2237
2238         /* safe to assume integers are NUL terminated? */
2239         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2240         if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX ) &&
2241                 errno == ERANGE )
2242         {
2243                 return LDAP_CONSTRAINT_VIOLATION;
2244         }
2245
2246         lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2247                 NULL, 10);
2248         if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX ) &&
2249                 errno == ERANGE )
2250         {
2251                 return LDAP_CONSTRAINT_VIOLATION;
2252         }
2253
2254         *matchp = (lValue | lAssertedValue) ? 0 : -1;
2255         return LDAP_SUCCESS;
2256 }
2257
2258 static int
2259 serialNumberAndIssuerValidate(
2260         Syntax *syntax,
2261         struct berval *in )
2262 {
2263         int rc;
2264         int state;
2265         ber_len_t n;
2266         struct berval sn, i;
2267         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2268
2269         i.bv_val = strchr( in->bv_val, '$' );
2270         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2271
2272         sn.bv_val = in->bv_val;
2273         sn.bv_len = i.bv_val - in->bv_val;
2274
2275         i.bv_val++;
2276         i.bv_len = in->bv_len - (sn.bv_len + 1);
2277
2278         /* validate serial number (strict for now) */
2279         for( n=0; n < sn.bv_len; n++ ) {
2280                 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2281         }
2282
2283         /* validate DN */
2284         rc = dnValidate( NULL, &i );
2285         if( rc ) return LDAP_INVALID_SYNTAX;
2286
2287         return LDAP_SUCCESS;
2288 }
2289
2290 int
2291 serialNumberAndIssuerPretty(
2292         Syntax *syntax,
2293         struct berval *val,
2294         struct berval *out,
2295         void *ctx )
2296 {
2297         int rc;
2298         int state;
2299         ber_len_t n;
2300         struct berval sn, i, newi;
2301
2302         assert( val );
2303         assert( out );
2304
2305         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
2306                 val->bv_val, 0, 0 );
2307
2308         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2309
2310         i.bv_val = strchr( val->bv_val, '$' );
2311         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2312
2313         sn.bv_val = val->bv_val;
2314         sn.bv_len = i.bv_val - val->bv_val;
2315
2316         i.bv_val++;
2317         i.bv_len = val->bv_len - (sn.bv_len + 1);
2318
2319         /* eat leading zeros */
2320         for( n=0; n < (sn.bv_len-1); n++ ) {
2321                 if( sn.bv_val[n] != '0' ) break;
2322         }
2323         sn.bv_val += n;
2324         sn.bv_len -= n;
2325
2326         for( n=0; n < sn.bv_len; n++ ) {
2327                 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2328         }
2329
2330         /* pretty DN */
2331         rc = dnPretty( syntax, &i, &newi, ctx );
2332         if( rc ) return LDAP_INVALID_SYNTAX;
2333
2334         /* make room from sn + "$" */
2335         out->bv_len = sn.bv_len + newi.bv_len + 1;
2336         out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2337
2338         if( BER_BVISNULL( out ) ) {
2339                 slap_sl_free( newi.bv_val, ctx );
2340                 return LDAP_OTHER;
2341         }
2342
2343         /* push issuer over */
2344         AC_MEMCPY( &out->bv_val[sn.bv_len+1], newi.bv_val, newi.bv_len );
2345         /* insert sn and "$" */
2346         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2347         out->bv_val[sn.bv_len] = '$';
2348         /* terminate */
2349         out->bv_val[out->bv_len] = '\0';
2350
2351         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
2352                 out->bv_val, 0, 0 );
2353
2354         return LDAP_SUCCESS;
2355 }
2356
2357 /*
2358  * This routine is called by certificateExactNormalize when
2359  * certificateExactNormalize receives a search string instead of
2360  * a certificate. This routine checks if the search value is valid
2361  * and then returns the normalized value
2362  */
2363 static int
2364 serialNumberAndIssuerNormalize(
2365         slap_mask_t usage,
2366         Syntax *syntax,
2367         MatchingRule *mr,
2368         struct berval *val,
2369         struct berval *out,
2370         void *ctx )
2371 {
2372         int rc;
2373         int state;
2374         ber_len_t n;
2375         struct berval sn, i, newi;
2376
2377         assert( val );
2378         assert( out );
2379
2380         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
2381                 val->bv_val, 0, 0 );
2382
2383         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2384
2385         i.bv_val = strchr( val->bv_val, '$' );
2386         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2387
2388         sn.bv_val = val->bv_val;
2389         sn.bv_len = i.bv_val - val->bv_val;
2390
2391         i.bv_val++;
2392         i.bv_len = val->bv_len - (sn.bv_len + 1);
2393
2394         /* eat leading zeros */
2395         for( n=0; n < (sn.bv_len-1); n++ ) {
2396                 if( sn.bv_val[n] != '0' ) break;
2397         }
2398         sn.bv_val += n;
2399         sn.bv_len -= n;
2400
2401         for( n=0; n < sn.bv_len; n++ ) {
2402                 if( !ASCII_DIGIT(sn.bv_val[n]) ) {
2403                         return LDAP_INVALID_SYNTAX;
2404                 }
2405         }
2406
2407         /* pretty DN */
2408         rc = dnNormalize( usage, syntax, mr, &i, &newi, ctx );
2409         if( rc ) return LDAP_INVALID_SYNTAX;
2410
2411         /* make room from sn + "$" */
2412         out->bv_len = sn.bv_len + newi.bv_len + 1;
2413         out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2414
2415         if( BER_BVISNULL( out ) ) {
2416                 slap_sl_free( newi.bv_val, ctx );
2417                 return LDAP_OTHER;
2418         }
2419
2420         /* push issuer over */
2421         AC_MEMCPY( &out->bv_val[sn.bv_len+1], newi.bv_val, newi.bv_len );
2422         /* insert sn and "$" */
2423         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2424         out->bv_val[sn.bv_len] = '$';
2425         /* terminate */
2426         out->bv_val[out->bv_len] = '\0';
2427
2428         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
2429                 out->bv_val, 0, 0 );
2430
2431         return rc;
2432 }
2433
2434 #ifdef HAVE_TLS
2435 static int
2436 certificateExactNormalize(
2437         slap_mask_t usage,
2438         Syntax *syntax,
2439         MatchingRule *mr,
2440         struct berval *val,
2441         struct berval *normalized,
2442         void *ctx )
2443 {
2444         int rc = LDAP_INVALID_SYNTAX;
2445         unsigned char *p;
2446         char *serial = NULL;
2447         ber_len_t seriallen;
2448         struct berval issuer_dn = BER_BVNULL;
2449         X509_NAME *name = NULL;
2450         ASN1_INTEGER *sn = NULL;
2451         X509 *xcert = NULL;
2452
2453         if( BER_BVISEMPTY( val ) ) goto done;
2454
2455         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
2456                 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
2457         }
2458
2459         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) );
2460
2461         p = (unsigned char *)val->bv_val;
2462         xcert = d2i_X509( NULL, &p, val->bv_len);
2463         if( xcert == NULL ) goto done;
2464
2465         sn=X509_get_serialNumber(xcert);
2466         if ( sn == NULL ) goto done;
2467         serial=i2s_ASN1_INTEGER(0, sn );
2468         if( serial == NULL ) goto done;
2469         seriallen=strlen(serial);
2470
2471         name=X509_get_issuer_name(xcert);
2472         if( name == NULL ) goto done;
2473         rc = dnX509normalize( name, &issuer_dn );
2474         if( rc != LDAP_SUCCESS ) goto done;
2475
2476         normalized->bv_len = seriallen + issuer_dn.bv_len + 1;
2477         normalized->bv_val = ch_malloc(normalized->bv_len+1);
2478         p = (unsigned char *)normalized->bv_val;
2479         AC_MEMCPY(p, serial, seriallen);
2480         p += seriallen;
2481         *p++ = '$';
2482         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
2483         p += issuer_dn.bv_len;
2484         *p = '\0';
2485
2486         Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
2487                 normalized->bv_val, NULL, NULL );
2488
2489 done:
2490         if (xcert) X509_free(xcert);
2491         if (serial) ch_free(serial);
2492         if (issuer_dn.bv_val) ber_memfree(issuer_dn.bv_val);
2493
2494         return rc;
2495 }
2496 #endif /* HAVE_TLS */
2497
2498
2499 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
2500 /* slight optimization - does not need the start parameter */
2501 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
2502 enum { start = 0 };
2503 #endif
2504
2505 static int
2506 check_time_syntax (struct berval *val,
2507         int start,
2508         int *parts,
2509         struct berval *fraction)
2510 {
2511         /*
2512          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
2513          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
2514          * GeneralizedTime supports leap seconds, UTCTime does not.
2515          */
2516         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
2517         static const int mdays[2][12] = {
2518                 /* non-leap years */
2519                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
2520                 /* leap years */
2521                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
2522         };
2523         char *p, *e;
2524         int part, c, c1, c2, tzoffset, leapyear = 0;
2525
2526         p = val->bv_val;
2527         e = p + val->bv_len;
2528
2529 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2530         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
2531 #endif
2532         for (part = start; part < 7 && p < e; part++) {
2533                 c1 = *p;
2534                 if (!ASCII_DIGIT(c1)) {
2535                         break;
2536                 }
2537                 p++;
2538                 if (p == e) {
2539                         return LDAP_INVALID_SYNTAX;
2540                 }
2541                 c = *p++;
2542                 if (!ASCII_DIGIT(c)) {
2543                         return LDAP_INVALID_SYNTAX;
2544                 }
2545                 c += c1 * 10 - '0' * 11;
2546                 if ((part | 1) == 3) {
2547                         --c;
2548                         if (c < 0) {
2549                                 return LDAP_INVALID_SYNTAX;
2550                         }
2551                 }
2552                 if (c >= ceiling[part]) {
2553                         if (! (c == 60 && part == 6 && start == 0))
2554                                 return LDAP_INVALID_SYNTAX;
2555                 }
2556                 parts[part] = c;
2557         }
2558         if (part < 5 + start) {
2559                 return LDAP_INVALID_SYNTAX;
2560         }
2561         for (; part < 9; part++) {
2562                 parts[part] = 0;
2563         }
2564
2565         /* leapyear check for the Gregorian calendar (year>1581) */
2566         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
2567                 leapyear = 1;
2568         }
2569
2570         if (parts[3] >= mdays[leapyear][parts[2]]) {
2571                 return LDAP_INVALID_SYNTAX;
2572         }
2573
2574         if (start == 0) {
2575                 fraction->bv_val = p;
2576                 fraction->bv_len = 0;
2577                 if (p < e && (*p == '.' || *p == ',')) {
2578                         char *end_num;
2579                         while (++p < e && ASCII_DIGIT(*p)) {
2580                                 /* EMTPY */;
2581                         }
2582                         if (p - fraction->bv_val == 1) {
2583                                 return LDAP_INVALID_SYNTAX;
2584                         }
2585                         for (end_num = p; end_num[-1] == '0'; --end_num) {
2586                                 /* EMPTY */;
2587                         }
2588                         c = end_num - fraction->bv_val;
2589                         if (c != 1) fraction->bv_len = c;
2590                 }
2591         }
2592
2593         if (p == e) {
2594                 /* no time zone */
2595                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2596         }
2597
2598         tzoffset = *p++;
2599         switch (tzoffset) {
2600         default:
2601                 return LDAP_INVALID_SYNTAX;
2602         case 'Z':
2603                 /* UTC */
2604                 break;
2605         case '+':
2606         case '-':
2607                 for (part = 7; part < 9 && p < e; part++) {
2608                         c1 = *p;
2609                         if (!ASCII_DIGIT(c1)) {
2610                                 break;
2611                         }
2612                         p++;
2613                         if (p == e) {
2614                                 return LDAP_INVALID_SYNTAX;
2615                         }
2616                         c2 = *p++;
2617                         if (!ASCII_DIGIT(c2)) {
2618                                 return LDAP_INVALID_SYNTAX;
2619                         }
2620                         parts[part] = c1 * 10 + c2 - '0' * 11;
2621                         if (parts[part] >= ceiling[part]) {
2622                                 return LDAP_INVALID_SYNTAX;
2623                         }
2624                 }
2625                 if (part < 8 + start) {
2626                         return LDAP_INVALID_SYNTAX;
2627                 }
2628
2629                 if (tzoffset == '-') {
2630                         /* negative offset to UTC, ie west of Greenwich */
2631                         parts[4] += parts[7];
2632                         parts[5] += parts[8];
2633                         /* offset is just hhmm, no seconds */
2634                         for (part = 6; --part >= 0; ) {
2635                                 if (part != 3) {
2636                                         c = ceiling[part];
2637                                 } else {
2638                                         c = mdays[leapyear][parts[2]];
2639                                 }
2640                                 if (parts[part] >= c) {
2641                                         if (part == 0) {
2642                                                 return LDAP_INVALID_SYNTAX;
2643                                         }
2644                                         parts[part] -= c;
2645                                         parts[part - 1]++;
2646                                         continue;
2647                                 } else if (part != 5) {
2648                                         break;
2649                                 }
2650                         }
2651                 } else {
2652                         /* positive offset to UTC, ie east of Greenwich */
2653                         parts[4] -= parts[7];
2654                         parts[5] -= parts[8];
2655                         for (part = 6; --part >= 0; ) {
2656                                 if (parts[part] < 0) {
2657                                         if (part == 0) {
2658                                                 return LDAP_INVALID_SYNTAX;
2659                                         }
2660                                         if (part != 3) {
2661                                                 c = ceiling[part];
2662                                         } else {
2663                                                 /* make first arg to % non-negative */
2664                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
2665                                         }
2666                                         parts[part] += c;
2667                                         parts[part - 1]--;
2668                                         continue;
2669                                 } else if (part != 5) {
2670                                         break;
2671                                 }
2672                         }
2673                 }
2674         }
2675
2676         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2677 }
2678
2679 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2680
2681 #if 0
2682 static int
2683 xutcTimeNormalize(
2684         Syntax *syntax,
2685         struct berval *val,
2686         struct berval *normalized )
2687 {
2688         int parts[9], rc;
2689
2690         rc = check_time_syntax(val, 1, parts, NULL);
2691         if (rc != LDAP_SUCCESS) {
2692                 return rc;
2693         }
2694
2695         normalized->bv_val = ch_malloc( 14 );
2696         if ( normalized->bv_val == NULL ) {
2697                 return LBER_ERROR_MEMORY;
2698         }
2699
2700         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
2701                 parts[1], parts[2] + 1, parts[3] + 1,
2702                 parts[4], parts[5], parts[6] );
2703         normalized->bv_len = 13;
2704
2705         return LDAP_SUCCESS;
2706 }
2707 #endif /* 0 */
2708
2709 static int
2710 utcTimeValidate(
2711         Syntax *syntax,
2712         struct berval *in )
2713 {
2714         int parts[9];
2715         return check_time_syntax(in, 1, parts, NULL);
2716 }
2717
2718 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
2719
2720 static int
2721 generalizedTimeValidate(
2722         Syntax *syntax,
2723         struct berval *in )
2724 {
2725         int parts[9];
2726         struct berval fraction;
2727         return check_time_syntax(in, 0, parts, &fraction);
2728 }
2729
2730 static int
2731 generalizedTimeNormalize(
2732         slap_mask_t usage,
2733         Syntax *syntax,
2734         MatchingRule *mr,
2735         struct berval *val,
2736         struct berval *normalized,
2737         void *ctx )
2738 {
2739         int parts[9], rc;
2740         unsigned int len;
2741         struct berval fraction;
2742
2743         rc = check_time_syntax(val, 0, parts, &fraction);
2744         if (rc != LDAP_SUCCESS) {
2745                 return rc;
2746         }
2747
2748         len = sizeof("YYYYmmddHHMMSSZ")-1 + fraction.bv_len;
2749         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
2750         if ( BER_BVISNULL( normalized ) ) {
2751                 return LBER_ERROR_MEMORY;
2752         }
2753
2754         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
2755                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
2756                 parts[4], parts[5], parts[6] );
2757         if ( !BER_BVISEMPTY( &fraction ) ) {
2758                 memcpy( normalized->bv_val + sizeof("YYYYmmddHHMMSSZ")-2,
2759                         fraction.bv_val, fraction.bv_len );
2760                 normalized->bv_val[sizeof("YYYYmmddHHMMSSZ")-2] = '.';
2761         }
2762         strcpy( normalized->bv_val + len-1, "Z" );
2763         normalized->bv_len = len;
2764
2765         return LDAP_SUCCESS;
2766 }
2767
2768 static int
2769 generalizedTimeOrderingMatch(
2770         int *matchp,
2771         slap_mask_t flags,
2772         Syntax *syntax,
2773         MatchingRule *mr,
2774         struct berval *value,
2775         void *assertedValue )
2776 {
2777         struct berval *asserted = (struct berval *) assertedValue;
2778         ber_len_t v_len  = value->bv_len;
2779         ber_len_t av_len = asserted->bv_len;
2780
2781         /* ignore trailing 'Z' when comparing */
2782         int match = memcmp( value->bv_val, asserted->bv_val,
2783                 (v_len < av_len ? v_len : av_len) - 1 );
2784         if ( match == 0 ) match = v_len - av_len;
2785
2786         *matchp = match;
2787         return LDAP_SUCCESS;
2788 }
2789
2790 /* Index generation function */
2791 int generalizedTimeIndexer(
2792         slap_mask_t use,
2793         slap_mask_t flags,
2794         Syntax *syntax,
2795         MatchingRule *mr,
2796         struct berval *prefix,
2797         BerVarray values,
2798         BerVarray *keysp,
2799         void *ctx )
2800 {
2801         int i, j;
2802         size_t slen, mlen;
2803         BerVarray keys;
2804         char tmp[5];
2805         BerValue bvtmp; /* 40 bit index */
2806         struct lutil_tm tm;
2807         struct lutil_timet tt;
2808
2809         bvtmp.bv_len = sizeof(tmp);
2810         bvtmp.bv_val = tmp;
2811         for( i=0; values[i].bv_val != NULL; i++ ) {
2812                 /* just count them */
2813         }
2814
2815         /* we should have at least one value at this point */
2816         assert( i > 0 );
2817
2818         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2819
2820         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
2821         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
2822                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
2823                 /* Use 40 bits of time for key */
2824                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
2825                         lutil_tm2time( &tm, &tt );
2826                         tmp[0] = tt.tt_gsec & 0xff;
2827                         tmp[4] = tt.tt_sec & 0xff;
2828                         tt.tt_sec >>= 8;
2829                         tmp[3] = tt.tt_sec & 0xff;
2830                         tt.tt_sec >>= 8;
2831                         tmp[2] = tt.tt_sec & 0xff;
2832                         tt.tt_sec >>= 8;
2833                         tmp[1] = tt.tt_sec & 0xff;
2834                         
2835                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
2836                 }
2837         }
2838
2839         keys[j].bv_val = NULL;
2840         keys[j].bv_len = 0;
2841
2842         *keysp = keys;
2843
2844         return LDAP_SUCCESS;
2845 }
2846
2847 /* Index generation function */
2848 int generalizedTimeFilter(
2849         slap_mask_t use,
2850         slap_mask_t flags,
2851         Syntax *syntax,
2852         MatchingRule *mr,
2853         struct berval *prefix,
2854         void * assertedValue,
2855         BerVarray *keysp,
2856         void *ctx )
2857 {
2858         BerVarray keys;
2859         char tmp[5];
2860         BerValue bvtmp; /* 40 bit index */
2861         BerValue *value = (BerValue *) assertedValue;
2862         struct lutil_tm tm;
2863         struct lutil_timet tt;
2864         
2865         bvtmp.bv_len = sizeof(tmp);
2866         bvtmp.bv_val = tmp;
2867         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
2868         /* Use 40 bits of time for key */
2869         if ( value->bv_val && value->bv_len >= 10 &&
2870                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
2871
2872                 lutil_tm2time( &tm, &tt );
2873                 tmp[0] = tt.tt_gsec & 0xff;
2874                 tmp[4] = tt.tt_sec & 0xff;
2875                 tt.tt_sec >>= 8;
2876                 tmp[3] = tt.tt_sec & 0xff;
2877                 tt.tt_sec >>= 8;
2878                 tmp[2] = tt.tt_sec & 0xff;
2879                 tt.tt_sec >>= 8;
2880                 tmp[1] = tt.tt_sec & 0xff;
2881
2882                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2883                 ber_dupbv_x(keys, &bvtmp, ctx );
2884                 keys[1].bv_val = NULL;
2885                 keys[1].bv_len = 0;
2886         } else {
2887                 keys = NULL;
2888         }
2889
2890         *keysp = keys;
2891
2892         return LDAP_SUCCESS;
2893 }
2894
2895 static int
2896 deliveryMethodValidate(
2897         Syntax *syntax,
2898         struct berval *val )
2899 {
2900 #undef LENOF
2901 #define LENOF(s) (sizeof(s)-1)
2902         struct berval tmp = *val;
2903         /*
2904      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
2905          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
2906          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
2907          */
2908 again:
2909         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2910
2911         switch( tmp.bv_val[0] ) {
2912         case 'a':
2913         case 'A':
2914                 if(( tmp.bv_len >= LENOF("any") ) &&
2915                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
2916                 {
2917                         tmp.bv_len -= LENOF("any");
2918                         tmp.bv_val += LENOF("any");
2919                         break;
2920                 }
2921                 return LDAP_INVALID_SYNTAX;
2922
2923         case 'm':
2924         case 'M':
2925                 if(( tmp.bv_len >= LENOF("mhs") ) &&
2926                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
2927                 {
2928                         tmp.bv_len -= LENOF("mhs");
2929                         tmp.bv_val += LENOF("mhs");
2930                         break;
2931                 }
2932                 return LDAP_INVALID_SYNTAX;
2933
2934         case 'p':
2935         case 'P':
2936                 if(( tmp.bv_len >= LENOF("physical") ) &&
2937                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
2938                 {
2939                         tmp.bv_len -= LENOF("physical");
2940                         tmp.bv_val += LENOF("physical");
2941                         break;
2942                 }
2943                 return LDAP_INVALID_SYNTAX;
2944
2945         case 't':
2946         case 'T': /* telex or teletex or telephone */
2947                 if(( tmp.bv_len >= LENOF("telex") ) &&
2948                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
2949                 {
2950                         tmp.bv_len -= LENOF("telex");
2951                         tmp.bv_val += LENOF("telex");
2952                         break;
2953                 }
2954                 if(( tmp.bv_len >= LENOF("teletex") ) &&
2955                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
2956                 {
2957                         tmp.bv_len -= LENOF("teletex");
2958                         tmp.bv_val += LENOF("teletex");
2959                         break;
2960                 }
2961                 if(( tmp.bv_len >= LENOF("telephone") ) &&
2962                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
2963                 {
2964                         tmp.bv_len -= LENOF("telephone");
2965                         tmp.bv_val += LENOF("telephone");
2966                         break;
2967                 }
2968                 return LDAP_INVALID_SYNTAX;
2969
2970         case 'g':
2971         case 'G': /* g3fax or g4fax */
2972                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
2973                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
2974                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
2975                 {
2976                         tmp.bv_len -= LENOF("g3fax");
2977                         tmp.bv_val += LENOF("g3fax");
2978                         break;
2979                 }
2980                 return LDAP_INVALID_SYNTAX;
2981
2982         case 'i':
2983         case 'I':
2984                 if(( tmp.bv_len >= LENOF("ia5") ) &&
2985                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
2986                 {
2987                         tmp.bv_len -= LENOF("ia5");
2988                         tmp.bv_val += LENOF("ia5");
2989                         break;
2990                 }
2991                 return LDAP_INVALID_SYNTAX;
2992
2993         case 'v':
2994         case 'V':
2995                 if(( tmp.bv_len >= LENOF("videotex") ) &&
2996                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
2997                 {
2998                         tmp.bv_len -= LENOF("videotex");
2999                         tmp.bv_val += LENOF("videotex");
3000                         break;
3001                 }
3002                 return LDAP_INVALID_SYNTAX;
3003
3004         default:
3005                 return LDAP_INVALID_SYNTAX;
3006         }
3007
3008         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
3009
3010         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3011                 tmp.bv_len++;
3012                 tmp.bv_val--;
3013         }
3014         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
3015                 tmp.bv_len++;
3016                 tmp.bv_val--;
3017         } else {
3018                 return LDAP_INVALID_SYNTAX;
3019         }
3020         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3021                 tmp.bv_len++;
3022                 tmp.bv_val--;
3023         }
3024
3025         goto again;
3026 }
3027
3028 static int
3029 nisNetgroupTripleValidate(
3030         Syntax *syntax,
3031         struct berval *val )
3032 {
3033         char *p, *e;
3034         int commas = 0;
3035
3036         if ( BER_BVISEMPTY( val ) ) {
3037                 return LDAP_INVALID_SYNTAX;
3038         }
3039
3040         p = (char *)val->bv_val;
3041         e = p + val->bv_len;
3042
3043         if ( *p != '(' /*')'*/ ) {
3044                 return LDAP_INVALID_SYNTAX;
3045         }
3046
3047         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
3048                 if ( *p == ',' ) {
3049                         commas++;
3050                         if ( commas > 2 ) {
3051                                 return LDAP_INVALID_SYNTAX;
3052                         }
3053
3054                 } else if ( !AD_CHAR( *p ) ) {
3055                         return LDAP_INVALID_SYNTAX;
3056                 }
3057         }
3058
3059         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
3060                 return LDAP_INVALID_SYNTAX;
3061         }
3062
3063         p++;
3064
3065         if (p != e) {
3066                 return LDAP_INVALID_SYNTAX;
3067         }
3068
3069         return LDAP_SUCCESS;
3070 }
3071
3072 static int
3073 bootParameterValidate(
3074         Syntax *syntax,
3075         struct berval *val )
3076 {
3077         char *p, *e;
3078
3079         if ( BER_BVISEMPTY( val ) ) {
3080                 return LDAP_INVALID_SYNTAX;
3081         }
3082
3083         p = (char *)val->bv_val;
3084         e = p + val->bv_len;
3085
3086         /* key */
3087         for (; ( p < e ) && ( *p != '=' ); p++ ) {
3088                 if ( !AD_CHAR( *p ) ) {
3089                         return LDAP_INVALID_SYNTAX;
3090                 }
3091         }
3092
3093         if ( *p != '=' ) {
3094                 return LDAP_INVALID_SYNTAX;
3095         }
3096
3097         /* server */
3098         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
3099                 if ( !AD_CHAR( *p ) ) {
3100                         return LDAP_INVALID_SYNTAX;
3101                 }
3102         }
3103
3104         if ( *p != ':' ) {
3105                 return LDAP_INVALID_SYNTAX;
3106         }
3107
3108         /* path */
3109         for ( p++; p < e; p++ ) {
3110                 if ( !SLAP_PRINTABLE( *p ) ) {
3111                         return LDAP_INVALID_SYNTAX;
3112                 }
3113         }
3114
3115         return LDAP_SUCCESS;
3116 }
3117
3118 static int
3119 firstComponentNormalize(
3120         slap_mask_t usage,
3121         Syntax *syntax,
3122         MatchingRule *mr,
3123         struct berval *val,
3124         struct berval *normalized,
3125         void *ctx )
3126 {
3127         int rc;
3128         struct berval comp;
3129         ber_len_t len;
3130
3131         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
3132                 ber_dupbv_x( normalized, val, ctx );
3133                 return LDAP_SUCCESS;
3134         }
3135
3136         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3137
3138         if( val->bv_val[0] != '(' /*')'*/ &&
3139                 val->bv_val[0] != '{' /*'}'*/ )
3140         {
3141                 return LDAP_INVALID_SYNTAX;
3142         }
3143
3144         /* trim leading white space */
3145         for( len=1;
3146                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
3147                 len++ )
3148         {
3149                 /* empty */
3150         }
3151
3152         /* grab next word */
3153         comp.bv_val = &val->bv_val[len];
3154         len = val->bv_len - len;
3155         for( comp.bv_len = 0;
3156                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
3157                 comp.bv_len++ )
3158         {
3159                 /* empty */
3160         }
3161
3162         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
3163                 rc = numericoidValidate( NULL, &comp );
3164         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
3165                 rc = integerValidate( NULL, &comp );
3166         } else {
3167                 rc = LDAP_INVALID_SYNTAX;
3168         }
3169         
3170
3171         if( rc == LDAP_SUCCESS ) {
3172                 ber_dupbv_x( normalized, &comp, ctx );
3173         }
3174
3175         return rc;
3176 }
3177
3178
3179 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
3180 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
3181
3182 static slap_syntax_defs_rec syntax_defs[] = {
3183         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
3184                 X_BINARY X_NOT_H_R ")",
3185                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL},
3186         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
3187                 0, NULL, NULL},
3188         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
3189                 0, NULL, NULL},
3190         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
3191                 X_NOT_H_R ")",
3192                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3193         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
3194                 X_NOT_H_R ")",
3195                 SLAP_SYNTAX_BER, berValidate, NULL},
3196         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
3197                 0, bitStringValidate, NULL },
3198         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
3199                 0, booleanValidate, NULL},
3200         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
3201                 X_BINARY X_NOT_H_R ")",
3202                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, certificateValidate, NULL},
3203         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
3204                 X_BINARY X_NOT_H_R ")",
3205                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3206         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
3207                 X_BINARY X_NOT_H_R ")",
3208                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3209         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
3210                 0, countryStringValidate, NULL},
3211         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
3212                 0, dnValidate, dnPretty},
3213         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
3214                 0, rdnValidate, rdnPretty},
3215 #ifdef LDAP_COMP_MATCH
3216         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
3217                 0, allComponentsValidate, NULL},
3218         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
3219                 0, componentFilterValidate, NULL},
3220 #endif
3221         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
3222                 0, NULL, NULL},
3223         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
3224                 0, deliveryMethodValidate, NULL},
3225         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
3226                 0, UTF8StringValidate, NULL},
3227         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
3228                 0, NULL, NULL},
3229         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
3230                 0, NULL, NULL},
3231         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
3232                 0, NULL, NULL},
3233         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
3234                 0, NULL, NULL},
3235         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
3236                 0, NULL, NULL},
3237         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
3238                 0, printablesStringValidate, NULL},
3239         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
3240                 SLAP_SYNTAX_BLOB, NULL, NULL},
3241         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
3242                 0, generalizedTimeValidate, NULL},
3243         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
3244                 0, NULL, NULL},
3245         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
3246                 0, IA5StringValidate, NULL},
3247         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
3248                 0, integerValidate, NULL},
3249         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
3250                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3251         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
3252                 0, NULL, NULL},
3253         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
3254                 0, NULL, NULL},
3255         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
3256                 0, NULL, NULL},
3257         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
3258                 0, NULL, NULL},
3259         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
3260                 0, NULL, NULL},
3261         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
3262                 0, nameUIDValidate, nameUIDPretty },
3263         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
3264                 0, NULL, NULL},
3265         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
3266                 0, numericStringValidate, NULL},
3267         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
3268                 0, NULL, NULL},
3269         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
3270                 0, numericoidValidate, NULL},
3271         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
3272                 0, IA5StringValidate, NULL},
3273         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
3274                 0, blobValidate, NULL},
3275         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
3276                 0, UTF8StringValidate, NULL},
3277         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
3278                 0, NULL, NULL},
3279         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
3280                 0, NULL, NULL},
3281         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
3282                 0, printableStringValidate, NULL},
3283         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
3284 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
3285                 0, subtreeSpecificationValidate, NULL},
3286         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
3287                 X_BINARY X_NOT_H_R ")",
3288                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
3289         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
3290                 0, printableStringValidate, NULL},
3291         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
3292                 0, NULL, NULL},
3293         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
3294                 0, printablesStringValidate, NULL},
3295 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3296         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
3297                 0, utcTimeValidate, NULL},
3298 #endif
3299         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
3300                 0, NULL, NULL},
3301         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
3302                 0, NULL, NULL},
3303         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
3304                 0, NULL, NULL},
3305         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
3306                 0, NULL, NULL},
3307         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
3308                 0, NULL, NULL},
3309
3310         /* RFC 2307 NIS Syntaxes */
3311         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
3312                 0, nisNetgroupTripleValidate, NULL},
3313         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
3314                 0, bootParameterValidate, NULL},
3315
3316         /* From PKIX *//* This OID is not published yet. */
3317         {"( 1.2.826.0.1.3344810.7.1 DESC 'Certificate Serial Number and Issuer' )",
3318                 SLAP_SYNTAX_HIDE,
3319                 serialNumberAndIssuerValidate,
3320                 serialNumberAndIssuerPretty},
3321
3322 #ifdef SLAPD_ACI_ENABLED
3323         /* OpenLDAP Experimental Syntaxes */
3324         {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
3325                 SLAP_SYNTAX_HIDE,
3326                 UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
3327                 NULL},
3328 #endif
3329
3330 #ifdef SLAPD_AUTHPASSWD
3331         /* needs updating */
3332         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
3333                 SLAP_SYNTAX_HIDE, NULL, NULL},
3334 #endif
3335
3336         {"( 1.3.6.1.4.1.4203.666.2.6 DESC 'UUID' )",
3337                 SLAP_SYNTAX_HIDE, UUIDValidate, NULL},
3338
3339         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
3340                 SLAP_SYNTAX_HIDE, csnValidate, NULL},
3341
3342         /* OpenLDAP Void Syntax */
3343         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
3344                 SLAP_SYNTAX_HIDE, inValidate, NULL},
3345         {NULL, 0, NULL, NULL}
3346 };
3347
3348 char *certificateExactMatchSyntaxes[] = {
3349         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
3350         NULL
3351 };
3352 #ifdef LDAP_COMP_MATCH
3353 char *componentFilterMatchSyntaxes[] = {
3354         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
3355         NULL
3356 };
3357 #endif
3358 char *directoryStringSyntaxes[] = {
3359         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
3360         NULL
3361 };
3362 char *integerFirstComponentMatchSyntaxes[] = {
3363         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
3364         "1.3.6.1.4.1.1466.115.121.1.17" /* ditStructureRuleDescription */,
3365         NULL
3366 };
3367 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
3368         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
3369         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
3370         "1.3.6.1.4.1.1466.115.121.1.16" /* ditContentRuleDescription */,
3371         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
3372         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
3373         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
3374         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
3375         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
3376         NULL
3377 };
3378
3379 /*
3380  * Other matching rules in X.520 that we do not use (yet):
3381  *
3382  * 2.5.13.25    uTCTimeMatch
3383  * 2.5.13.26    uTCTimeOrderingMatch
3384  * 2.5.13.31*   directoryStringFirstComponentMatch
3385  * 2.5.13.32*   wordMatch
3386  * 2.5.13.33*   keywordMatch
3387  * 2.5.13.36    certificatePairExactMatch
3388  * 2.5.13.37    certificatePairMatch
3389  * 2.5.13.38    certificateListExactMatch
3390  * 2.5.13.39    certificateListMatch
3391  * 2.5.13.40    algorithmIdentifierMatch
3392  * 2.5.13.41*   storedPrefixMatch
3393  * 2.5.13.42    attributeCertificateMatch
3394  * 2.5.13.43    readerAndKeyIDMatch
3395  * 2.5.13.44    attributeIntegrityMatch
3396  *
3397  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
3398  */
3399 static slap_mrule_defs_rec mrule_defs[] = {
3400         /*
3401          * EQUALITY matching rules must be listed after associated APPROX
3402          * matching rules.  So, we list all APPROX matching rules first.
3403          */
3404         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
3405                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3406                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3407                 NULL, NULL, directoryStringApproxMatch,
3408                 directoryStringApproxIndexer, directoryStringApproxFilter,
3409                 NULL},
3410
3411         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
3412                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3413                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3414                 NULL, NULL, IA5StringApproxMatch,
3415                 IA5StringApproxIndexer, IA5StringApproxFilter,
3416                 NULL},
3417
3418         /*
3419          * Other matching rules
3420          */
3421         
3422         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
3423                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3424                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3425                 NULL, NULL, octetStringMatch,
3426                 octetStringIndexer, octetStringFilter,
3427                 NULL },
3428
3429         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
3430                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3431                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3432                 NULL, dnNormalize, dnMatch,
3433                 octetStringIndexer, octetStringFilter,
3434                 NULL },
3435
3436         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
3437                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3438                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3439                 NULL, dnNormalize, dnRelativeMatch,
3440                 NULL, NULL,
3441                 NULL },
3442
3443         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
3444                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3445                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3446                 NULL, dnNormalize, dnRelativeMatch,
3447                 NULL, NULL,
3448                 NULL },
3449
3450         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
3451                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3452                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3453                 NULL, dnNormalize, dnRelativeMatch,
3454                 NULL, NULL,
3455                 NULL },
3456
3457         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
3458                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3459                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3460                 NULL, dnNormalize, dnRelativeMatch,
3461                 NULL, NULL,
3462                 NULL },
3463
3464         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
3465                 "SYNTAX 1.2.36.79672281.1.5.0 )",
3466                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3467                 NULL, rdnNormalize, rdnMatch,
3468                 octetStringIndexer, octetStringFilter,
3469                 NULL },
3470
3471 #ifdef LDAP_COMP_MATCH
3472         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
3473                 "SYNTAX 1.2.36.79672281.1.5.2 )",
3474                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
3475                 NULL, NULL , componentFilterMatch,
3476                 octetStringIndexer, octetStringFilter,
3477                 NULL },
3478
3479         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
3480                 "SYNTAX 1.2.36.79672281.1.5.3 )",
3481                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
3482                 NULL, NULL , allComponentsMatch,
3483                 octetStringIndexer, octetStringFilter,
3484                 NULL },
3485
3486         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
3487                 "SYNTAX 1.2.36.79672281.1.5.3 )",
3488                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
3489                 NULL, NULL , directoryComponentsMatch,
3490                 octetStringIndexer, octetStringFilter,
3491                 NULL },
3492 #endif
3493
3494         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
3495                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3496                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3497                 NULL, UTF8StringNormalize, octetStringMatch,
3498                 octetStringIndexer, octetStringFilter,
3499                 directoryStringApproxMatchOID },
3500
3501         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
3502                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3503                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3504                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3505                 NULL, NULL,
3506                 "caseIgnoreMatch" },
3507
3508         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
3509                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3510                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3511                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
3512                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3513                 "caseIgnoreMatch" },
3514
3515         {"( 2.5.13.5 NAME 'caseExactMatch' "
3516                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3517                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3518                 NULL, UTF8StringNormalize, octetStringMatch,
3519                 octetStringIndexer, octetStringFilter,
3520                 directoryStringApproxMatchOID },
3521
3522         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
3523                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3524                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3525                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3526                 NULL, NULL,
3527                 "caseExactMatch" },
3528
3529         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
3530                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3531                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3532                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
3533                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3534                 "caseExactMatch" },
3535
3536         {"( 2.5.13.8 NAME 'numericStringMatch' "
3537                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3538                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3539                 NULL, numericStringNormalize, octetStringMatch,
3540                 octetStringIndexer, octetStringFilter,
3541                 NULL },
3542
3543         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
3544                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3545                 SLAP_MR_ORDERING, NULL,
3546                 NULL, numericStringNormalize, octetStringOrderingMatch,
3547                 NULL, NULL,
3548                 "numericStringMatch" },
3549
3550         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
3551                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3552                 SLAP_MR_SUBSTR, NULL,
3553                 NULL, numericStringNormalize, octetStringSubstringsMatch,
3554                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3555                 "numericStringMatch" },
3556
3557         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
3558                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
3559                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3560                 NULL, NULL, NULL, NULL, NULL, NULL },
3561
3562         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
3563                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3564                 SLAP_MR_SUBSTR, NULL,
3565                 NULL, NULL, NULL, NULL, NULL,
3566                 "caseIgnoreListMatch" },
3567
3568         {"( 2.5.13.13 NAME 'booleanMatch' "
3569                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
3570                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3571                 NULL, NULL, booleanMatch,
3572                 octetStringIndexer, octetStringFilter,
3573                 NULL },
3574
3575         {"( 2.5.13.14 NAME 'integerMatch' "
3576                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3577                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3578                 NULL, NULL, integerMatch,
3579                 octetStringIndexer, octetStringFilter,
3580                 NULL },
3581
3582         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
3583                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3584                 SLAP_MR_ORDERING, NULL,
3585                 NULL, NULL, integerMatch,
3586                 NULL, NULL,
3587                 "integerMatch" },
3588
3589         {"( 2.5.13.16 NAME 'bitStringMatch' "
3590                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
3591                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3592                 NULL, NULL, octetStringMatch,
3593                 octetStringIndexer, octetStringFilter,
3594                 NULL },
3595
3596         {"( 2.5.13.17 NAME 'octetStringMatch' "
3597                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3598                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3599                 NULL, NULL, octetStringMatch,
3600                 octetStringIndexer, octetStringFilter,
3601                 NULL },
3602
3603         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
3604                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3605                 SLAP_MR_ORDERING, NULL,
3606                 NULL, NULL, octetStringOrderingMatch,
3607                 NULL, NULL,
3608                 "octetStringMatch" },
3609
3610         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
3611                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3612                 SLAP_MR_SUBSTR, NULL,
3613                 NULL, NULL, octetStringSubstringsMatch,
3614                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3615                 "octetStringMatch" },
3616
3617         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
3618                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
3619                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3620                 NULL,
3621                 telephoneNumberNormalize, octetStringMatch,
3622                 octetStringIndexer, octetStringFilter,
3623                 NULL },
3624
3625         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
3626                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3627                 SLAP_MR_SUBSTR, NULL,
3628                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
3629                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3630                 "telephoneNumberMatch" },
3631
3632         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
3633                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
3634                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3635                 NULL, NULL, NULL, NULL, NULL, NULL },
3636
3637         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
3638                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
3639                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3640                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
3641                 NULL, NULL,
3642                 NULL },
3643
3644         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
3645                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
3646                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3647                 NULL, NULL, NULL, NULL, NULL, NULL },
3648
3649         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
3650                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3651                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
3652                 NULL, generalizedTimeNormalize, octetStringMatch,
3653                 generalizedTimeIndexer, generalizedTimeFilter,
3654                 NULL },
3655
3656         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
3657                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3658                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
3659                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
3660                 NULL, NULL,
3661                 "generalizedTimeMatch" },
3662
3663         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
3664                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3665                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3666                         integerFirstComponentMatchSyntaxes,
3667                 NULL, firstComponentNormalize, integerMatch,
3668                 octetStringIndexer, octetStringFilter,
3669                 NULL },
3670
3671         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
3672                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3673                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3674                         objectIdentifierFirstComponentMatchSyntaxes,
3675                 NULL, firstComponentNormalize, octetStringMatch,
3676                 octetStringIndexer, octetStringFilter,
3677                 NULL },
3678
3679         {"( 2.5.13.34 NAME 'certificateExactMatch' "
3680                 "SYNTAX 1.2.826.0.1.3344810.7.1 )",
3681                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
3682 #ifdef HAVE_TLS
3683                 NULL, certificateExactNormalize, octetStringMatch,
3684                 octetStringIndexer, octetStringFilter,
3685 #else
3686                 NULL, NULL, NULL, NULL, NULL,
3687 #endif
3688                 NULL },
3689
3690         {"( 2.5.13.35 NAME 'certificateMatch' "
3691                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )",
3692                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3693 #ifdef HAVE_TLS
3694                 NULL, NULL, octetStringMatch,
3695                 octetStringIndexer, octetStringFilter,
3696 #else
3697                 NULL, NULL, NULL, NULL, NULL,
3698 #endif
3699                 NULL },
3700
3701         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
3702                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3703                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3704                 NULL, IA5StringNormalize, octetStringMatch,
3705                 octetStringIndexer, octetStringFilter,
3706                 IA5StringApproxMatchOID },
3707
3708         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
3709                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3710                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3711                 NULL, IA5StringNormalize, octetStringMatch,
3712                 octetStringIndexer, octetStringFilter,
3713                 IA5StringApproxMatchOID },
3714
3715         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
3716                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3717                 SLAP_MR_SUBSTR, NULL,
3718                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
3719                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3720                 "caseIgnoreIA5Match" },
3721
3722         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
3723                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3724                 SLAP_MR_SUBSTR, NULL,
3725                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
3726                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3727                 "caseExactIA5Match" },
3728
3729 #ifdef SLAPD_AUTHPASSWD
3730         /* needs updating */
3731         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
3732                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3733                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3734                 NULL, NULL, authPasswordMatch,
3735                 NULL, NULL,
3736                 NULL},
3737 #endif
3738
3739 #ifdef SLAPD_ACI_ENABLED
3740         {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
3741                 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
3742                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3743                 NULL, NULL, OpenLDAPaciMatch,
3744                 NULL, NULL,
3745                 NULL},
3746 #endif
3747
3748         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
3749                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3750                 SLAP_MR_EXT, NULL,
3751                 NULL, NULL, integerBitAndMatch,
3752                 NULL, NULL,
3753                 "integerMatch" },
3754
3755         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
3756                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3757                 SLAP_MR_EXT, NULL,
3758                 NULL, NULL, integerBitOrMatch,
3759                 NULL, NULL,
3760                 "integerMatch" },
3761
3762         {"( 1.3.6.1.4.1.4203.666.4.6 NAME 'UUIDMatch' "
3763                 "SYNTAX 1.3.6.1.4.1.4203.666.2.6 )",
3764                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3765                 NULL, UUIDNormalize, octetStringMatch,
3766                 octetStringIndexer, octetStringFilter,
3767                 NULL},
3768
3769         {"( 1.3.6.1.4.1.4203.666.4.7 NAME 'UUIDOrderingMatch' "
3770                 "SYNTAX 1.3.6.1.4.1.4203.666.2.6 )",
3771                 SLAP_MR_HIDE | SLAP_MR_ORDERING, NULL,
3772                 NULL, UUIDNormalize, octetStringOrderingMatch,
3773                 octetStringIndexer, octetStringFilter,
3774                 "UUIDMatch"},
3775
3776         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
3777                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
3778                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
3779                 NULL, NULL, csnMatch,
3780                 csnIndexer, csnFilter,
3781                 NULL},
3782
3783         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
3784                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
3785                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
3786                 NULL, NULL, csnOrderingMatch,
3787                 NULL, NULL,
3788                 "CSNMatch" },
3789
3790         {NULL, SLAP_MR_NONE, NULL,
3791                 NULL, NULL, NULL, NULL, NULL,
3792                 NULL }
3793 };
3794
3795 int
3796 slap_schema_init( void )
3797 {
3798         int             res;
3799         int             i;
3800
3801         /* we should only be called once (from main) */
3802         assert( schema_init_done == 0 );
3803
3804         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
3805                 res = register_syntax( &syntax_defs[i] );
3806
3807                 if ( res ) {
3808                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
3809                                  syntax_defs[i].sd_desc );
3810                         return LDAP_OTHER;
3811                 }
3812         }
3813
3814         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
3815                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
3816                         mrule_defs[i].mrd_compat_syntaxes == NULL )
3817                 {
3818                         fprintf( stderr,
3819                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
3820                                  mrule_defs[i].mrd_desc );
3821                         continue;
3822                 }
3823
3824                 res = register_matching_rule( &mrule_defs[i] );
3825
3826                 if ( res ) {
3827                         fprintf( stderr,
3828                                 "slap_schema_init: Error registering matching rule %s\n",
3829                                  mrule_defs[i].mrd_desc );
3830                         return LDAP_OTHER;
3831                 }
3832         }
3833
3834         res = slap_schema_load();
3835         schema_init_done = 1;
3836         return res;
3837 }
3838
3839 void
3840 schema_destroy( void )
3841 {
3842         oidm_destroy();
3843         oc_destroy();
3844         at_destroy();
3845         mr_destroy();
3846         mru_destroy();
3847         syn_destroy();
3848 }