]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
ITS#3773 additional fix
[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, j, len, 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 len, max, 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 );
896         assert( out );
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) ? 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 : -1;
2356         return LDAP_SUCCESS;
2357 }
2358
2359 static int
2360 serialNumberAndIssuerValidate(
2361         Syntax *syntax,
2362         struct berval *in )
2363 {
2364         int rc;
2365         int state;
2366         ber_len_t n;
2367         struct berval sn, i;
2368         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2369
2370         i.bv_val = strchr( in->bv_val, '$' );
2371         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2372
2373         sn.bv_val = in->bv_val;
2374         sn.bv_len = i.bv_val - in->bv_val;
2375
2376         i.bv_val++;
2377         i.bv_len = in->bv_len - (sn.bv_len + 1);
2378
2379         /* validate serial number (strict for now) */
2380         for( n=0; n < sn.bv_len; n++ ) {
2381                 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2382         }
2383
2384         /* validate DN */
2385         rc = dnValidate( NULL, &i );
2386         if( rc ) return LDAP_INVALID_SYNTAX;
2387
2388         return LDAP_SUCCESS;
2389 }
2390
2391 int
2392 serialNumberAndIssuerPretty(
2393         Syntax *syntax,
2394         struct berval *val,
2395         struct berval *out,
2396         void *ctx )
2397 {
2398         int rc;
2399         int state;
2400         ber_len_t n;
2401         struct berval sn, i, newi;
2402
2403         assert( val );
2404         assert( out );
2405
2406         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
2407                 val->bv_val, 0, 0 );
2408
2409         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2410
2411         i.bv_val = strchr( val->bv_val, '$' );
2412         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2413
2414         sn.bv_val = val->bv_val;
2415         sn.bv_len = i.bv_val - val->bv_val;
2416
2417         i.bv_val++;
2418         i.bv_len = val->bv_len - (sn.bv_len + 1);
2419
2420         /* eat leading zeros */
2421         for( n=0; n < (sn.bv_len-1); n++ ) {
2422                 if( sn.bv_val[n] != '0' ) break;
2423         }
2424         sn.bv_val += n;
2425         sn.bv_len -= n;
2426
2427         for( n=0; n < sn.bv_len; n++ ) {
2428                 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2429         }
2430
2431         /* pretty DN */
2432         rc = dnPretty( syntax, &i, &newi, ctx );
2433         if( rc ) return LDAP_INVALID_SYNTAX;
2434
2435         /* make room from sn + "$" */
2436         out->bv_len = sn.bv_len + newi.bv_len + 1;
2437         out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2438
2439         if( BER_BVISNULL( out ) ) {
2440                 slap_sl_free( newi.bv_val, ctx );
2441                 return LDAP_OTHER;
2442         }
2443
2444         /* push issuer over */
2445         AC_MEMCPY( &out->bv_val[sn.bv_len+1], newi.bv_val, newi.bv_len );
2446         /* insert sn and "$" */
2447         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2448         out->bv_val[sn.bv_len] = '$';
2449         /* terminate */
2450         out->bv_val[out->bv_len] = '\0';
2451
2452         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
2453                 out->bv_val, 0, 0 );
2454
2455         return LDAP_SUCCESS;
2456 }
2457
2458 /*
2459  * This routine is called by certificateExactNormalize when
2460  * certificateExactNormalize receives a search string instead of
2461  * a certificate. This routine checks if the search value is valid
2462  * and then returns the normalized value
2463  */
2464 static int
2465 serialNumberAndIssuerNormalize(
2466         slap_mask_t usage,
2467         Syntax *syntax,
2468         MatchingRule *mr,
2469         struct berval *val,
2470         struct berval *out,
2471         void *ctx )
2472 {
2473         int rc;
2474         int state;
2475         ber_len_t n;
2476         struct berval sn, i, newi;
2477
2478         assert( val );
2479         assert( out );
2480
2481         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
2482                 val->bv_val, 0, 0 );
2483
2484         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2485
2486         i.bv_val = strchr( val->bv_val, '$' );
2487         if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2488
2489         sn.bv_val = val->bv_val;
2490         sn.bv_len = i.bv_val - val->bv_val;
2491
2492         i.bv_val++;
2493         i.bv_len = val->bv_len - (sn.bv_len + 1);
2494
2495         /* eat leading zeros */
2496         for( n=0; n < (sn.bv_len-1); n++ ) {
2497                 if( sn.bv_val[n] != '0' ) break;
2498         }
2499         sn.bv_val += n;
2500         sn.bv_len -= n;
2501
2502         for( n=0; n < sn.bv_len; n++ ) {
2503                 if( !ASCII_DIGIT(sn.bv_val[n]) ) {
2504                         return LDAP_INVALID_SYNTAX;
2505                 }
2506         }
2507
2508         /* pretty DN */
2509         rc = dnNormalize( usage, syntax, mr, &i, &newi, ctx );
2510         if( rc ) return LDAP_INVALID_SYNTAX;
2511
2512         /* make room from sn + "$" */
2513         out->bv_len = sn.bv_len + newi.bv_len + 1;
2514         out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2515
2516         if( BER_BVISNULL( out ) ) {
2517                 slap_sl_free( newi.bv_val, ctx );
2518                 return LDAP_OTHER;
2519         }
2520
2521         /* push issuer over */
2522         AC_MEMCPY( &out->bv_val[sn.bv_len+1], newi.bv_val, newi.bv_len );
2523         /* insert sn and "$" */
2524         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2525         out->bv_val[sn.bv_len] = '$';
2526         /* terminate */
2527         out->bv_val[out->bv_len] = '\0';
2528
2529         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
2530                 out->bv_val, 0, 0 );
2531
2532         return rc;
2533 }
2534
2535 #ifdef HAVE_TLS
2536 static int
2537 certificateExactNormalize(
2538         slap_mask_t usage,
2539         Syntax *syntax,
2540         MatchingRule *mr,
2541         struct berval *val,
2542         struct berval *normalized,
2543         void *ctx )
2544 {
2545         int rc = LDAP_INVALID_SYNTAX;
2546         unsigned char *p;
2547         char *serial = NULL;
2548         ber_len_t seriallen;
2549         struct berval issuer_dn = BER_BVNULL;
2550         X509_NAME *name = NULL;
2551         ASN1_INTEGER *sn = NULL;
2552         X509 *xcert = NULL;
2553
2554         if( BER_BVISEMPTY( val ) ) goto done;
2555
2556         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
2557                 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
2558         }
2559
2560         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) );
2561
2562         p = (unsigned char *)val->bv_val;
2563         xcert = d2i_X509( NULL, &p, val->bv_len);
2564         if( xcert == NULL ) goto done;
2565
2566         sn=X509_get_serialNumber(xcert);
2567         if ( sn == NULL ) goto done;
2568         serial=i2s_ASN1_INTEGER(0, sn );
2569         if( serial == NULL ) goto done;
2570         seriallen=strlen(serial);
2571
2572         name=X509_get_issuer_name(xcert);
2573         if( name == NULL ) goto done;
2574         rc = dnX509normalize( name, &issuer_dn );
2575         if( rc != LDAP_SUCCESS ) goto done;
2576
2577         normalized->bv_len = seriallen + issuer_dn.bv_len + 1;
2578         normalized->bv_val = ch_malloc(normalized->bv_len+1);
2579         p = (unsigned char *)normalized->bv_val;
2580         AC_MEMCPY(p, serial, seriallen);
2581         p += seriallen;
2582         *p++ = '$';
2583         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
2584         p += issuer_dn.bv_len;
2585         *p = '\0';
2586
2587         Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
2588                 normalized->bv_val, NULL, NULL );
2589
2590 done:
2591         if (xcert) X509_free(xcert);
2592         if (serial) ch_free(serial);
2593         if (issuer_dn.bv_val) ber_memfree(issuer_dn.bv_val);
2594
2595         return rc;
2596 }
2597 #endif /* HAVE_TLS */
2598
2599
2600 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
2601 /* slight optimization - does not need the start parameter */
2602 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
2603 enum { start = 0 };
2604 #endif
2605
2606 static int
2607 check_time_syntax (struct berval *val,
2608         int start,
2609         int *parts,
2610         struct berval *fraction)
2611 {
2612         /*
2613          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
2614          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
2615          * GeneralizedTime supports leap seconds, UTCTime does not.
2616          */
2617         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
2618         static const int mdays[2][12] = {
2619                 /* non-leap years */
2620                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
2621                 /* leap years */
2622                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
2623         };
2624         char *p, *e;
2625         int part, c, c1, c2, tzoffset, leapyear = 0;
2626
2627         p = val->bv_val;
2628         e = p + val->bv_len;
2629
2630 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2631         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
2632 #endif
2633         for (part = start; part < 7 && p < e; part++) {
2634                 c1 = *p;
2635                 if (!ASCII_DIGIT(c1)) {
2636                         break;
2637                 }
2638                 p++;
2639                 if (p == e) {
2640                         return LDAP_INVALID_SYNTAX;
2641                 }
2642                 c = *p++;
2643                 if (!ASCII_DIGIT(c)) {
2644                         return LDAP_INVALID_SYNTAX;
2645                 }
2646                 c += c1 * 10 - '0' * 11;
2647                 if ((part | 1) == 3) {
2648                         --c;
2649                         if (c < 0) {
2650                                 return LDAP_INVALID_SYNTAX;
2651                         }
2652                 }
2653                 if (c >= ceiling[part]) {
2654                         if (! (c == 60 && part == 6 && start == 0))
2655                                 return LDAP_INVALID_SYNTAX;
2656                 }
2657                 parts[part] = c;
2658         }
2659         if (part < 5 + start) {
2660                 return LDAP_INVALID_SYNTAX;
2661         }
2662         for (; part < 9; part++) {
2663                 parts[part] = 0;
2664         }
2665
2666         /* leapyear check for the Gregorian calendar (year>1581) */
2667         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
2668                 leapyear = 1;
2669         }
2670
2671         if (parts[3] >= mdays[leapyear][parts[2]]) {
2672                 return LDAP_INVALID_SYNTAX;
2673         }
2674
2675         if (start == 0) {
2676                 fraction->bv_val = p;
2677                 fraction->bv_len = 0;
2678                 if (p < e && (*p == '.' || *p == ',')) {
2679                         char *end_num;
2680                         while (++p < e && ASCII_DIGIT(*p)) {
2681                                 /* EMTPY */;
2682                         }
2683                         if (p - fraction->bv_val == 1) {
2684                                 return LDAP_INVALID_SYNTAX;
2685                         }
2686                         for (end_num = p; end_num[-1] == '0'; --end_num) {
2687                                 /* EMPTY */;
2688                         }
2689                         c = end_num - fraction->bv_val;
2690                         if (c != 1) fraction->bv_len = c;
2691                 }
2692         }
2693
2694         if (p == e) {
2695                 /* no time zone */
2696                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2697         }
2698
2699         tzoffset = *p++;
2700         switch (tzoffset) {
2701         default:
2702                 return LDAP_INVALID_SYNTAX;
2703         case 'Z':
2704                 /* UTC */
2705                 break;
2706         case '+':
2707         case '-':
2708                 for (part = 7; part < 9 && p < e; part++) {
2709                         c1 = *p;
2710                         if (!ASCII_DIGIT(c1)) {
2711                                 break;
2712                         }
2713                         p++;
2714                         if (p == e) {
2715                                 return LDAP_INVALID_SYNTAX;
2716                         }
2717                         c2 = *p++;
2718                         if (!ASCII_DIGIT(c2)) {
2719                                 return LDAP_INVALID_SYNTAX;
2720                         }
2721                         parts[part] = c1 * 10 + c2 - '0' * 11;
2722                         if (parts[part] >= ceiling[part]) {
2723                                 return LDAP_INVALID_SYNTAX;
2724                         }
2725                 }
2726                 if (part < 8 + start) {
2727                         return LDAP_INVALID_SYNTAX;
2728                 }
2729
2730                 if (tzoffset == '-') {
2731                         /* negative offset to UTC, ie west of Greenwich */
2732                         parts[4] += parts[7];
2733                         parts[5] += parts[8];
2734                         /* offset is just hhmm, no seconds */
2735                         for (part = 6; --part >= 0; ) {
2736                                 if (part != 3) {
2737                                         c = ceiling[part];
2738                                 } else {
2739                                         c = mdays[leapyear][parts[2]];
2740                                 }
2741                                 if (parts[part] >= c) {
2742                                         if (part == 0) {
2743                                                 return LDAP_INVALID_SYNTAX;
2744                                         }
2745                                         parts[part] -= c;
2746                                         parts[part - 1]++;
2747                                         continue;
2748                                 } else if (part != 5) {
2749                                         break;
2750                                 }
2751                         }
2752                 } else {
2753                         /* positive offset to UTC, ie east of Greenwich */
2754                         parts[4] -= parts[7];
2755                         parts[5] -= parts[8];
2756                         for (part = 6; --part >= 0; ) {
2757                                 if (parts[part] < 0) {
2758                                         if (part == 0) {
2759                                                 return LDAP_INVALID_SYNTAX;
2760                                         }
2761                                         if (part != 3) {
2762                                                 c = ceiling[part];
2763                                         } else {
2764                                                 /* make first arg to % non-negative */
2765                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
2766                                         }
2767                                         parts[part] += c;
2768                                         parts[part - 1]--;
2769                                         continue;
2770                                 } else if (part != 5) {
2771                                         break;
2772                                 }
2773                         }
2774                 }
2775         }
2776
2777         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2778 }
2779
2780 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2781
2782 #if 0
2783 static int
2784 xutcTimeNormalize(
2785         Syntax *syntax,
2786         struct berval *val,
2787         struct berval *normalized )
2788 {
2789         int parts[9], rc;
2790
2791         rc = check_time_syntax(val, 1, parts, NULL);
2792         if (rc != LDAP_SUCCESS) {
2793                 return rc;
2794         }
2795
2796         normalized->bv_val = ch_malloc( 14 );
2797         if ( normalized->bv_val == NULL ) {
2798                 return LBER_ERROR_MEMORY;
2799         }
2800
2801         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
2802                 parts[1], parts[2] + 1, parts[3] + 1,
2803                 parts[4], parts[5], parts[6] );
2804         normalized->bv_len = 13;
2805
2806         return LDAP_SUCCESS;
2807 }
2808 #endif /* 0 */
2809
2810 static int
2811 utcTimeValidate(
2812         Syntax *syntax,
2813         struct berval *in )
2814 {
2815         int parts[9];
2816         return check_time_syntax(in, 1, parts, NULL);
2817 }
2818
2819 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
2820
2821 static int
2822 generalizedTimeValidate(
2823         Syntax *syntax,
2824         struct berval *in )
2825 {
2826         int parts[9];
2827         struct berval fraction;
2828         return check_time_syntax(in, 0, parts, &fraction);
2829 }
2830
2831 static int
2832 generalizedTimeNormalize(
2833         slap_mask_t usage,
2834         Syntax *syntax,
2835         MatchingRule *mr,
2836         struct berval *val,
2837         struct berval *normalized,
2838         void *ctx )
2839 {
2840         int parts[9], rc;
2841         unsigned int len;
2842         struct berval fraction;
2843
2844         rc = check_time_syntax(val, 0, parts, &fraction);
2845         if (rc != LDAP_SUCCESS) {
2846                 return rc;
2847         }
2848
2849         len = sizeof("YYYYmmddHHMMSSZ")-1 + fraction.bv_len;
2850         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
2851         if ( BER_BVISNULL( normalized ) ) {
2852                 return LBER_ERROR_MEMORY;
2853         }
2854
2855         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
2856                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
2857                 parts[4], parts[5], parts[6] );
2858         if ( !BER_BVISEMPTY( &fraction ) ) {
2859                 memcpy( normalized->bv_val + sizeof("YYYYmmddHHMMSSZ")-2,
2860                         fraction.bv_val, fraction.bv_len );
2861                 normalized->bv_val[sizeof("YYYYmmddHHMMSSZ")-2] = '.';
2862         }
2863         strcpy( normalized->bv_val + len-1, "Z" );
2864         normalized->bv_len = len;
2865
2866         return LDAP_SUCCESS;
2867 }
2868
2869 static int
2870 generalizedTimeOrderingMatch(
2871         int *matchp,
2872         slap_mask_t flags,
2873         Syntax *syntax,
2874         MatchingRule *mr,
2875         struct berval *value,
2876         void *assertedValue )
2877 {
2878         struct berval *asserted = (struct berval *) assertedValue;
2879         ber_len_t v_len  = value->bv_len;
2880         ber_len_t av_len = asserted->bv_len;
2881
2882         /* ignore trailing 'Z' when comparing */
2883         int match = memcmp( value->bv_val, asserted->bv_val,
2884                 (v_len < av_len ? v_len : av_len) - 1 );
2885         if ( match == 0 ) match = v_len - av_len;
2886
2887         *matchp = match;
2888         return LDAP_SUCCESS;
2889 }
2890
2891 /* Index generation function */
2892 int generalizedTimeIndexer(
2893         slap_mask_t use,
2894         slap_mask_t flags,
2895         Syntax *syntax,
2896         MatchingRule *mr,
2897         struct berval *prefix,
2898         BerVarray values,
2899         BerVarray *keysp,
2900         void *ctx )
2901 {
2902         int i, j;
2903         size_t slen, mlen;
2904         BerVarray keys;
2905         char tmp[5];
2906         BerValue bvtmp; /* 40 bit index */
2907         struct lutil_tm tm;
2908         struct lutil_timet tt;
2909
2910         bvtmp.bv_len = sizeof(tmp);
2911         bvtmp.bv_val = tmp;
2912         for( i=0; values[i].bv_val != NULL; i++ ) {
2913                 /* just count them */
2914         }
2915
2916         /* we should have at least one value at this point */
2917         assert( i > 0 );
2918
2919         keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2920
2921         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
2922         for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
2923                 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
2924                 /* Use 40 bits of time for key */
2925                 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
2926                         lutil_tm2time( &tm, &tt );
2927                         tmp[0] = tt.tt_gsec & 0xff;
2928                         tmp[4] = tt.tt_sec & 0xff;
2929                         tt.tt_sec >>= 8;
2930                         tmp[3] = tt.tt_sec & 0xff;
2931                         tt.tt_sec >>= 8;
2932                         tmp[2] = tt.tt_sec & 0xff;
2933                         tt.tt_sec >>= 8;
2934                         tmp[1] = tt.tt_sec & 0xff;
2935                         
2936                         ber_dupbv_x(&keys[j++], &bvtmp, ctx );
2937                 }
2938         }
2939
2940         keys[j].bv_val = NULL;
2941         keys[j].bv_len = 0;
2942
2943         *keysp = keys;
2944
2945         return LDAP_SUCCESS;
2946 }
2947
2948 /* Index generation function */
2949 int generalizedTimeFilter(
2950         slap_mask_t use,
2951         slap_mask_t flags,
2952         Syntax *syntax,
2953         MatchingRule *mr,
2954         struct berval *prefix,
2955         void * assertedValue,
2956         BerVarray *keysp,
2957         void *ctx )
2958 {
2959         BerVarray keys;
2960         char tmp[5];
2961         BerValue bvtmp; /* 40 bit index */
2962         BerValue *value = (BerValue *) assertedValue;
2963         struct lutil_tm tm;
2964         struct lutil_timet tt;
2965         
2966         bvtmp.bv_len = sizeof(tmp);
2967         bvtmp.bv_val = tmp;
2968         /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
2969         /* Use 40 bits of time for key */
2970         if ( value->bv_val && value->bv_len >= 10 &&
2971                 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
2972
2973                 lutil_tm2time( &tm, &tt );
2974                 tmp[0] = tt.tt_gsec & 0xff;
2975                 tmp[4] = tt.tt_sec & 0xff;
2976                 tt.tt_sec >>= 8;
2977                 tmp[3] = tt.tt_sec & 0xff;
2978                 tt.tt_sec >>= 8;
2979                 tmp[2] = tt.tt_sec & 0xff;
2980                 tt.tt_sec >>= 8;
2981                 tmp[1] = tt.tt_sec & 0xff;
2982
2983                 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2984                 ber_dupbv_x(keys, &bvtmp, ctx );
2985                 keys[1].bv_val = NULL;
2986                 keys[1].bv_len = 0;
2987         } else {
2988                 keys = NULL;
2989         }
2990
2991         *keysp = keys;
2992
2993         return LDAP_SUCCESS;
2994 }
2995
2996 static int
2997 deliveryMethodValidate(
2998         Syntax *syntax,
2999         struct berval *val )
3000 {
3001 #undef LENOF
3002 #define LENOF(s) (sizeof(s)-1)
3003         struct berval tmp = *val;
3004         /*
3005      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
3006          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
3007          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
3008          */
3009 again:
3010         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3011
3012         switch( tmp.bv_val[0] ) {
3013         case 'a':
3014         case 'A':
3015                 if(( tmp.bv_len >= LENOF("any") ) &&
3016                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
3017                 {
3018                         tmp.bv_len -= LENOF("any");
3019                         tmp.bv_val += LENOF("any");
3020                         break;
3021                 }
3022                 return LDAP_INVALID_SYNTAX;
3023
3024         case 'm':
3025         case 'M':
3026                 if(( tmp.bv_len >= LENOF("mhs") ) &&
3027                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
3028                 {
3029                         tmp.bv_len -= LENOF("mhs");
3030                         tmp.bv_val += LENOF("mhs");
3031                         break;
3032                 }
3033                 return LDAP_INVALID_SYNTAX;
3034
3035         case 'p':
3036         case 'P':
3037                 if(( tmp.bv_len >= LENOF("physical") ) &&
3038                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
3039                 {
3040                         tmp.bv_len -= LENOF("physical");
3041                         tmp.bv_val += LENOF("physical");
3042                         break;
3043                 }
3044                 return LDAP_INVALID_SYNTAX;
3045
3046         case 't':
3047         case 'T': /* telex or teletex or telephone */
3048                 if(( tmp.bv_len >= LENOF("telex") ) &&
3049                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
3050                 {
3051                         tmp.bv_len -= LENOF("telex");
3052                         tmp.bv_val += LENOF("telex");
3053                         break;
3054                 }
3055                 if(( tmp.bv_len >= LENOF("teletex") ) &&
3056                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
3057                 {
3058                         tmp.bv_len -= LENOF("teletex");
3059                         tmp.bv_val += LENOF("teletex");
3060                         break;
3061                 }
3062                 if(( tmp.bv_len >= LENOF("telephone") ) &&
3063                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
3064                 {
3065                         tmp.bv_len -= LENOF("telephone");
3066                         tmp.bv_val += LENOF("telephone");
3067                         break;
3068                 }
3069                 return LDAP_INVALID_SYNTAX;
3070
3071         case 'g':
3072         case 'G': /* g3fax or g4fax */
3073                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
3074                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
3075                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
3076                 {
3077                         tmp.bv_len -= LENOF("g3fax");
3078                         tmp.bv_val += LENOF("g3fax");
3079                         break;
3080                 }
3081                 return LDAP_INVALID_SYNTAX;
3082
3083         case 'i':
3084         case 'I':
3085                 if(( tmp.bv_len >= LENOF("ia5") ) &&
3086                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
3087                 {
3088                         tmp.bv_len -= LENOF("ia5");
3089                         tmp.bv_val += LENOF("ia5");
3090                         break;
3091                 }
3092                 return LDAP_INVALID_SYNTAX;
3093
3094         case 'v':
3095         case 'V':
3096                 if(( tmp.bv_len >= LENOF("videotex") ) &&
3097                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
3098                 {
3099                         tmp.bv_len -= LENOF("videotex");
3100                         tmp.bv_val += LENOF("videotex");
3101                         break;
3102                 }
3103                 return LDAP_INVALID_SYNTAX;
3104
3105         default:
3106                 return LDAP_INVALID_SYNTAX;
3107         }
3108
3109         if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
3110
3111         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3112                 tmp.bv_len++;
3113                 tmp.bv_val--;
3114         }
3115         if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
3116                 tmp.bv_len++;
3117                 tmp.bv_val--;
3118         } else {
3119                 return LDAP_INVALID_SYNTAX;
3120         }
3121         while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3122                 tmp.bv_len++;
3123                 tmp.bv_val--;
3124         }
3125
3126         goto again;
3127 }
3128
3129 static int
3130 nisNetgroupTripleValidate(
3131         Syntax *syntax,
3132         struct berval *val )
3133 {
3134         char *p, *e;
3135         int commas = 0;
3136
3137         if ( BER_BVISEMPTY( val ) ) {
3138                 return LDAP_INVALID_SYNTAX;
3139         }
3140
3141         p = (char *)val->bv_val;
3142         e = p + val->bv_len;
3143
3144         if ( *p != '(' /*')'*/ ) {
3145                 return LDAP_INVALID_SYNTAX;
3146         }
3147
3148         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
3149                 if ( *p == ',' ) {
3150                         commas++;
3151                         if ( commas > 2 ) {
3152                                 return LDAP_INVALID_SYNTAX;
3153                         }
3154
3155                 } else if ( !AD_CHAR( *p ) ) {
3156                         return LDAP_INVALID_SYNTAX;
3157                 }
3158         }
3159
3160         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
3161                 return LDAP_INVALID_SYNTAX;
3162         }
3163
3164         p++;
3165
3166         if (p != e) {
3167                 return LDAP_INVALID_SYNTAX;
3168         }
3169
3170         return LDAP_SUCCESS;
3171 }
3172
3173 static int
3174 bootParameterValidate(
3175         Syntax *syntax,
3176         struct berval *val )
3177 {
3178         char *p, *e;
3179
3180         if ( BER_BVISEMPTY( val ) ) {
3181                 return LDAP_INVALID_SYNTAX;
3182         }
3183
3184         p = (char *)val->bv_val;
3185         e = p + val->bv_len;
3186
3187         /* key */
3188         for (; ( p < e ) && ( *p != '=' ); p++ ) {
3189                 if ( !AD_CHAR( *p ) ) {
3190                         return LDAP_INVALID_SYNTAX;
3191                 }
3192         }
3193
3194         if ( *p != '=' ) {
3195                 return LDAP_INVALID_SYNTAX;
3196         }
3197
3198         /* server */
3199         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
3200                 if ( !AD_CHAR( *p ) ) {
3201                         return LDAP_INVALID_SYNTAX;
3202                 }
3203         }
3204
3205         if ( *p != ':' ) {
3206                 return LDAP_INVALID_SYNTAX;
3207         }
3208
3209         /* path */
3210         for ( p++; p < e; p++ ) {
3211                 if ( !SLAP_PRINTABLE( *p ) ) {
3212                         return LDAP_INVALID_SYNTAX;
3213                 }
3214         }
3215
3216         return LDAP_SUCCESS;
3217 }
3218
3219 static int
3220 firstComponentNormalize(
3221         slap_mask_t usage,
3222         Syntax *syntax,
3223         MatchingRule *mr,
3224         struct berval *val,
3225         struct berval *normalized,
3226         void *ctx )
3227 {
3228         int rc;
3229         struct berval comp;
3230         ber_len_t len;
3231
3232         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
3233                 ber_dupbv_x( normalized, val, ctx );
3234                 return LDAP_SUCCESS;
3235         }
3236
3237         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3238
3239         if( val->bv_val[0] != '(' /*')'*/ &&
3240                 val->bv_val[0] != '{' /*'}'*/ )
3241         {
3242                 return LDAP_INVALID_SYNTAX;
3243         }
3244
3245         /* trim leading white space */
3246         for( len=1;
3247                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
3248                 len++ )
3249         {
3250                 /* empty */
3251         }
3252
3253         /* grab next word */
3254         comp.bv_val = &val->bv_val[len];
3255         len = val->bv_len - len;
3256         for( comp.bv_len = 0;
3257                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
3258                 comp.bv_len++ )
3259         {
3260                 /* empty */
3261         }
3262
3263         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
3264                 rc = numericoidValidate( NULL, &comp );
3265         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
3266                 rc = integerValidate( NULL, &comp );
3267         } else {
3268                 rc = LDAP_INVALID_SYNTAX;
3269         }
3270         
3271
3272         if( rc == LDAP_SUCCESS ) {
3273                 ber_dupbv_x( normalized, &comp, ctx );
3274         }
3275
3276         return rc;
3277 }
3278
3279
3280 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
3281 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
3282
3283 static slap_syntax_defs_rec syntax_defs[] = {
3284         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
3285                 X_BINARY X_NOT_H_R ")",
3286                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL},
3287         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
3288                 0, NULL, NULL},
3289         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
3290                 0, NULL, NULL},
3291         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
3292                 X_NOT_H_R ")",
3293                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3294         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
3295                 X_NOT_H_R ")",
3296                 SLAP_SYNTAX_BER, berValidate, NULL},
3297         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
3298                 0, bitStringValidate, NULL },
3299         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
3300                 0, booleanValidate, NULL},
3301         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
3302                 X_BINARY X_NOT_H_R ")",
3303                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, certificateValidate, NULL},
3304         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
3305                 X_BINARY X_NOT_H_R ")",
3306                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3307         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
3308                 X_BINARY X_NOT_H_R ")",
3309                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3310         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
3311                 0, countryStringValidate, NULL},
3312         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
3313                 0, dnValidate, dnPretty},
3314         {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
3315                 0, rdnValidate, rdnPretty},
3316 #ifdef LDAP_COMP_MATCH
3317         {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
3318                 0, allComponentsValidate, NULL},
3319         {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
3320                 0, componentFilterValidate, NULL},
3321 #endif
3322         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
3323                 0, NULL, NULL},
3324         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
3325                 0, deliveryMethodValidate, NULL},
3326         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
3327                 0, UTF8StringValidate, NULL},
3328         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
3329                 0, NULL, NULL},
3330         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
3331                 0, NULL, NULL},
3332         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
3333                 0, NULL, NULL},
3334         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
3335                 0, NULL, NULL},
3336         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
3337                 0, NULL, NULL},
3338         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
3339                 0, printablesStringValidate, NULL},
3340         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
3341                 SLAP_SYNTAX_BLOB, NULL, NULL},
3342         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
3343                 0, generalizedTimeValidate, NULL},
3344         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
3345                 0, NULL, NULL},
3346         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
3347                 0, IA5StringValidate, NULL},
3348         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
3349                 0, integerValidate, NULL},
3350         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
3351                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3352         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
3353                 0, NULL, NULL},
3354         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
3355                 0, NULL, NULL},
3356         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
3357                 0, NULL, NULL},
3358         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
3359                 0, NULL, NULL},
3360         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
3361                 0, NULL, NULL},
3362         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
3363                 0, nameUIDValidate, nameUIDPretty },
3364         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
3365                 0, NULL, NULL},
3366         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
3367                 0, numericStringValidate, NULL},
3368         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
3369                 0, NULL, NULL},
3370         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
3371                 0, numericoidValidate, NULL},
3372         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
3373                 0, IA5StringValidate, NULL},
3374         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
3375                 0, blobValidate, NULL},
3376         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
3377                 0, UTF8StringValidate, NULL},
3378         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
3379                 0, NULL, NULL},
3380         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
3381                 0, NULL, NULL},
3382         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
3383                 0, printableStringValidate, NULL},
3384         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
3385 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
3386                 0, subtreeSpecificationValidate, NULL},
3387         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
3388                 X_BINARY X_NOT_H_R ")",
3389                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
3390         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
3391                 0, printableStringValidate, NULL},
3392         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
3393                 0, NULL, NULL},
3394         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
3395                 0, printablesStringValidate, NULL},
3396 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3397         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
3398                 0, utcTimeValidate, NULL},
3399 #endif
3400         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
3401                 0, NULL, NULL},
3402         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
3403                 0, NULL, NULL},
3404         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
3405                 0, NULL, NULL},
3406         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
3407                 0, NULL, NULL},
3408         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
3409                 0, NULL, NULL},
3410
3411         /* RFC 2307 NIS Syntaxes */
3412         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
3413                 0, nisNetgroupTripleValidate, NULL},
3414         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
3415                 0, bootParameterValidate, NULL},
3416
3417         /* From PKIX *//* This OID is not published yet. */
3418         {"( 1.2.826.0.1.3344810.7.1 DESC 'Certificate Serial Number and Issuer' )",
3419                 SLAP_SYNTAX_HIDE,
3420                 serialNumberAndIssuerValidate,
3421                 serialNumberAndIssuerPretty},
3422
3423 #ifdef SLAPD_ACI_ENABLED
3424         /* OpenLDAP Experimental Syntaxes */
3425         {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
3426                 SLAP_SYNTAX_HIDE,
3427                 UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
3428                 NULL},
3429 #endif
3430
3431 #ifdef SLAPD_AUTHPASSWD
3432         /* needs updating */
3433         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
3434                 SLAP_SYNTAX_HIDE, NULL, NULL},
3435 #endif
3436
3437         {"( 1.3.6.1.4.1.4203.666.2.6 DESC 'UUID' )",
3438                 SLAP_SYNTAX_HIDE, UUIDValidate, NULL},
3439
3440         {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
3441                 SLAP_SYNTAX_HIDE, csnValidate, NULL},
3442
3443         /* OpenLDAP Void Syntax */
3444         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
3445                 SLAP_SYNTAX_HIDE, inValidate, NULL},
3446         {NULL, 0, NULL, NULL}
3447 };
3448
3449 char *certificateExactMatchSyntaxes[] = {
3450         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
3451         NULL
3452 };
3453 #ifdef LDAP_COMP_MATCH
3454 char *componentFilterMatchSyntaxes[] = {
3455         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
3456         NULL
3457 };
3458 #endif
3459 char *directoryStringSyntaxes[] = {
3460         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
3461         NULL
3462 };
3463 char *integerFirstComponentMatchSyntaxes[] = {
3464         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
3465         "1.3.6.1.4.1.1466.115.121.1.17" /* ditStructureRuleDescription */,
3466         NULL
3467 };
3468 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
3469         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
3470         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
3471         "1.3.6.1.4.1.1466.115.121.1.16" /* ditContentRuleDescription */,
3472         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
3473         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
3474         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
3475         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
3476         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
3477         NULL
3478 };
3479
3480 /*
3481  * Other matching rules in X.520 that we do not use (yet):
3482  *
3483  * 2.5.13.25    uTCTimeMatch
3484  * 2.5.13.26    uTCTimeOrderingMatch
3485  * 2.5.13.31*   directoryStringFirstComponentMatch
3486  * 2.5.13.32*   wordMatch
3487  * 2.5.13.33*   keywordMatch
3488  * 2.5.13.36    certificatePairExactMatch
3489  * 2.5.13.37    certificatePairMatch
3490  * 2.5.13.38    certificateListExactMatch
3491  * 2.5.13.39    certificateListMatch
3492  * 2.5.13.40    algorithmIdentifierMatch
3493  * 2.5.13.41*   storedPrefixMatch
3494  * 2.5.13.42    attributeCertificateMatch
3495  * 2.5.13.43    readerAndKeyIDMatch
3496  * 2.5.13.44    attributeIntegrityMatch
3497  *
3498  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
3499  */
3500 static slap_mrule_defs_rec mrule_defs[] = {
3501         /*
3502          * EQUALITY matching rules must be listed after associated APPROX
3503          * matching rules.  So, we list all APPROX matching rules first.
3504          */
3505         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
3506                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3507                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3508                 NULL, NULL, directoryStringApproxMatch,
3509                 directoryStringApproxIndexer, directoryStringApproxFilter,
3510                 NULL},
3511
3512         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
3513                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3514                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3515                 NULL, NULL, IA5StringApproxMatch,
3516                 IA5StringApproxIndexer, IA5StringApproxFilter,
3517                 NULL},
3518
3519         /*
3520          * Other matching rules
3521          */
3522         
3523         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
3524                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3525                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3526                 NULL, NULL, octetStringMatch,
3527                 octetStringIndexer, octetStringFilter,
3528                 NULL },
3529
3530         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
3531                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3532                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3533                 NULL, dnNormalize, dnMatch,
3534                 octetStringIndexer, octetStringFilter,
3535                 NULL },
3536
3537         {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
3538                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3539                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3540                 NULL, dnNormalize, dnRelativeMatch,
3541                 NULL, NULL,
3542                 NULL },
3543
3544         {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
3545                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3546                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3547                 NULL, dnNormalize, dnRelativeMatch,
3548                 NULL, NULL,
3549                 NULL },
3550
3551         {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
3552                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3553                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3554                 NULL, dnNormalize, dnRelativeMatch,
3555                 NULL, NULL,
3556                 NULL },
3557
3558         {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
3559                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3560                 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3561                 NULL, dnNormalize, dnRelativeMatch,
3562                 NULL, NULL,
3563                 NULL },
3564
3565         {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
3566                 "SYNTAX 1.2.36.79672281.1.5.0 )",
3567                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3568                 NULL, rdnNormalize, rdnMatch,
3569                 octetStringIndexer, octetStringFilter,
3570                 NULL },
3571
3572 #ifdef LDAP_COMP_MATCH
3573         {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
3574                 "SYNTAX 1.2.36.79672281.1.5.2 )",
3575                 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
3576                 NULL, NULL , componentFilterMatch,
3577                 octetStringIndexer, octetStringFilter,
3578                 NULL },
3579
3580         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
3581                 "SYNTAX 1.2.36.79672281.1.5.3 )",
3582                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
3583                 NULL, NULL , allComponentsMatch,
3584                 octetStringIndexer, octetStringFilter,
3585                 NULL },
3586
3587         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
3588                 "SYNTAX 1.2.36.79672281.1.5.3 )",
3589                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
3590                 NULL, NULL , directoryComponentsMatch,
3591                 octetStringIndexer, octetStringFilter,
3592                 NULL },
3593 #endif
3594
3595         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
3596                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3597                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3598                 NULL, UTF8StringNormalize, octetStringMatch,
3599                 octetStringIndexer, octetStringFilter,
3600                 directoryStringApproxMatchOID },
3601
3602         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
3603                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3604                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3605                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3606                 NULL, NULL,
3607                 "caseIgnoreMatch" },
3608
3609         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
3610                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3611                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3612                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
3613                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3614                 "caseIgnoreMatch" },
3615
3616         {"( 2.5.13.5 NAME 'caseExactMatch' "
3617                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3618                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3619                 NULL, UTF8StringNormalize, octetStringMatch,
3620                 octetStringIndexer, octetStringFilter,
3621                 directoryStringApproxMatchOID },
3622
3623         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
3624                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3625                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3626                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3627                 NULL, NULL,
3628                 "caseExactMatch" },
3629
3630         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
3631                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3632                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3633                 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
3634                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3635                 "caseExactMatch" },
3636
3637         {"( 2.5.13.8 NAME 'numericStringMatch' "
3638                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3639                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3640                 NULL, numericStringNormalize, octetStringMatch,
3641                 octetStringIndexer, octetStringFilter,
3642                 NULL },
3643
3644         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
3645                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3646                 SLAP_MR_ORDERING, NULL,
3647                 NULL, numericStringNormalize, octetStringOrderingMatch,
3648                 NULL, NULL,
3649                 "numericStringMatch" },
3650
3651         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
3652                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3653                 SLAP_MR_SUBSTR, NULL,
3654                 NULL, numericStringNormalize, octetStringSubstringsMatch,
3655                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3656                 "numericStringMatch" },
3657
3658         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
3659                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
3660                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3661                 NULL, NULL, NULL, NULL, NULL, NULL },
3662
3663         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
3664                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3665                 SLAP_MR_SUBSTR, NULL,
3666                 NULL, NULL, NULL, NULL, NULL,
3667                 "caseIgnoreListMatch" },
3668
3669         {"( 2.5.13.13 NAME 'booleanMatch' "
3670                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
3671                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3672                 NULL, NULL, booleanMatch,
3673                 octetStringIndexer, octetStringFilter,
3674                 NULL },
3675
3676         {"( 2.5.13.14 NAME 'integerMatch' "
3677                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3678                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3679                 NULL, NULL, integerMatch,
3680                 octetStringIndexer, octetStringFilter,
3681                 NULL },
3682
3683         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
3684                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3685                 SLAP_MR_ORDERING, NULL,
3686                 NULL, NULL, integerMatch,
3687                 NULL, NULL,
3688                 "integerMatch" },
3689
3690         {"( 2.5.13.16 NAME 'bitStringMatch' "
3691                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
3692                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3693                 NULL, NULL, octetStringMatch,
3694                 octetStringIndexer, octetStringFilter,
3695                 NULL },
3696
3697         {"( 2.5.13.17 NAME 'octetStringMatch' "
3698                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3699                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3700                 NULL, NULL, octetStringMatch,
3701                 octetStringIndexer, octetStringFilter,
3702                 NULL },
3703
3704         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
3705                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3706                 SLAP_MR_ORDERING, NULL,
3707                 NULL, NULL, octetStringOrderingMatch,
3708                 NULL, NULL,
3709                 "octetStringMatch" },
3710
3711         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
3712                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3713                 SLAP_MR_SUBSTR, NULL,
3714                 NULL, NULL, octetStringSubstringsMatch,
3715                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3716                 "octetStringMatch" },
3717
3718         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
3719                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
3720                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3721                 NULL,
3722                 telephoneNumberNormalize, octetStringMatch,
3723                 octetStringIndexer, octetStringFilter,
3724                 NULL },
3725
3726         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
3727                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3728                 SLAP_MR_SUBSTR, NULL,
3729                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
3730                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3731                 "telephoneNumberMatch" },
3732
3733         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
3734                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
3735                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3736                 NULL, NULL, NULL, NULL, NULL, NULL },
3737
3738         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
3739                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
3740                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3741                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
3742                 uniqueMemberIndexer, uniqueMemberFilter,
3743                 NULL },
3744
3745         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
3746                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
3747                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3748                 NULL, NULL, NULL, NULL, NULL, NULL },
3749
3750         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
3751                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3752                 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
3753                 NULL, generalizedTimeNormalize, octetStringMatch,
3754                 generalizedTimeIndexer, generalizedTimeFilter,
3755                 NULL },
3756
3757         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
3758                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3759                 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
3760                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
3761                 NULL, NULL,
3762                 "generalizedTimeMatch" },
3763
3764         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
3765                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3766                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3767                         integerFirstComponentMatchSyntaxes,
3768                 NULL, firstComponentNormalize, integerMatch,
3769                 octetStringIndexer, octetStringFilter,
3770                 NULL },
3771
3772         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
3773                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3774                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3775                         objectIdentifierFirstComponentMatchSyntaxes,
3776                 NULL, firstComponentNormalize, octetStringMatch,
3777                 octetStringIndexer, octetStringFilter,
3778                 NULL },
3779
3780         {"( 2.5.13.34 NAME 'certificateExactMatch' "
3781                 "SYNTAX 1.2.826.0.1.3344810.7.1 )",
3782                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
3783 #ifdef HAVE_TLS
3784                 NULL, certificateExactNormalize, octetStringMatch,
3785                 octetStringIndexer, octetStringFilter,
3786 #else
3787                 NULL, NULL, NULL, NULL, NULL,
3788 #endif
3789                 NULL },
3790
3791         {"( 2.5.13.35 NAME 'certificateMatch' "
3792                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )",
3793                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3794 #ifdef HAVE_TLS
3795                 NULL, NULL, octetStringMatch,
3796                 octetStringIndexer, octetStringFilter,
3797 #else
3798                 NULL, NULL, NULL, NULL, NULL,
3799 #endif
3800                 NULL },
3801
3802         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
3803                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3804                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3805                 NULL, IA5StringNormalize, octetStringMatch,
3806                 octetStringIndexer, octetStringFilter,
3807                 IA5StringApproxMatchOID },
3808
3809         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
3810                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3811                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3812                 NULL, IA5StringNormalize, octetStringMatch,
3813                 octetStringIndexer, octetStringFilter,
3814                 IA5StringApproxMatchOID },
3815
3816         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
3817                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3818                 SLAP_MR_SUBSTR, NULL,
3819                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
3820                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3821                 "caseIgnoreIA5Match" },
3822
3823         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
3824                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3825                 SLAP_MR_SUBSTR, NULL,
3826                 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
3827                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3828                 "caseExactIA5Match" },
3829
3830 #ifdef SLAPD_AUTHPASSWD
3831         /* needs updating */
3832         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
3833                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3834                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3835                 NULL, NULL, authPasswordMatch,
3836                 NULL, NULL,
3837                 NULL},
3838 #endif
3839
3840 #ifdef SLAPD_ACI_ENABLED
3841         {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
3842                 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
3843                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3844                 NULL, NULL, OpenLDAPaciMatch,
3845                 NULL, NULL,
3846                 NULL},
3847 #endif
3848
3849         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
3850                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3851                 SLAP_MR_EXT, NULL,
3852                 NULL, NULL, integerBitAndMatch,
3853                 NULL, NULL,
3854                 "integerMatch" },
3855
3856         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
3857                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3858                 SLAP_MR_EXT, NULL,
3859                 NULL, NULL, integerBitOrMatch,
3860                 NULL, NULL,
3861                 "integerMatch" },
3862
3863         {"( 1.3.6.1.4.1.4203.666.4.6 NAME 'UUIDMatch' "
3864                 "SYNTAX 1.3.6.1.4.1.4203.666.2.6 )",
3865                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3866                 NULL, UUIDNormalize, octetStringMatch,
3867                 octetStringIndexer, octetStringFilter,
3868                 NULL},
3869
3870         {"( 1.3.6.1.4.1.4203.666.4.7 NAME 'UUIDOrderingMatch' "
3871                 "SYNTAX 1.3.6.1.4.1.4203.666.2.6 )",
3872                 SLAP_MR_HIDE | SLAP_MR_ORDERING, NULL,
3873                 NULL, UUIDNormalize, octetStringOrderingMatch,
3874                 octetStringIndexer, octetStringFilter,
3875                 "UUIDMatch"},
3876
3877         {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
3878                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
3879                 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
3880                 NULL, NULL, csnMatch,
3881                 csnIndexer, csnFilter,
3882                 NULL},
3883
3884         {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
3885                 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
3886                 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
3887                 NULL, NULL, csnOrderingMatch,
3888                 NULL, NULL,
3889                 "CSNMatch" },
3890
3891         {NULL, SLAP_MR_NONE, NULL,
3892                 NULL, NULL, NULL, NULL, NULL,
3893                 NULL }
3894 };
3895
3896 int
3897 slap_schema_init( void )
3898 {
3899         int             res;
3900         int             i;
3901
3902         /* we should only be called once (from main) */
3903         assert( schema_init_done == 0 );
3904
3905         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
3906                 res = register_syntax( &syntax_defs[i] );
3907
3908                 if ( res ) {
3909                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
3910                                  syntax_defs[i].sd_desc );
3911                         return LDAP_OTHER;
3912                 }
3913         }
3914
3915         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
3916                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
3917                         mrule_defs[i].mrd_compat_syntaxes == NULL )
3918                 {
3919                         fprintf( stderr,
3920                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
3921                                  mrule_defs[i].mrd_desc );
3922                         continue;
3923                 }
3924
3925                 res = register_matching_rule( &mrule_defs[i] );
3926
3927                 if ( res ) {
3928                         fprintf( stderr,
3929                                 "slap_schema_init: Error registering matching rule %s\n",
3930                                  mrule_defs[i].mrd_desc );
3931                         return LDAP_OTHER;
3932                 }
3933         }
3934
3935         res = slap_schema_load();
3936         schema_init_done = 1;
3937         return res;
3938 }
3939
3940 void
3941 schema_destroy( void )
3942 {
3943         oidm_destroy();
3944         oc_destroy();
3945         at_destroy();
3946         mr_destroy();
3947         mru_destroy();
3948         syn_destroy();
3949 }