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