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