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