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