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