]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
b5f9a2b239fd18bbd358b3be37110f5a229ae968
[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 #ifdef NEW_LOGGING
927         LDAP_LOG( OPERATION, ARGS, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
928 #else
929         Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
930 #endif
931
932         if( val->bv_len == 0 ) {
933                 ber_dupbv_x( out, val, ctx );
934
935         } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
936                 return LDAP_INVALID_SYNTAX;
937
938         } else {
939                 int             rc;
940                 struct berval   dnval = *val;
941                 struct berval   uidval = BER_BVNULL;
942
943                 uidval.bv_val = strrchr( val->bv_val, '#' );
944                 if ( uidval.bv_val ) {
945                         uidval.bv_val++;
946                         uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
947
948                         rc = bitStringValidate( NULL, &uidval );
949
950                         if ( rc == LDAP_SUCCESS ) {
951                                 ber_dupbv_x( &dnval, val, ctx );
952                                 dnval.bv_len -= uidval.bv_len + 1;
953                                 dnval.bv_val[dnval.bv_len] = '\0';
954
955                         } else {
956                                 uidval.bv_val = NULL;
957                         }
958                 }
959
960                 rc = dnPretty( syntax, &dnval, out, ctx );
961                 if ( dnval.bv_val != val->bv_val ) {
962                         slap_sl_free( dnval.bv_val, ctx );
963                 }
964                 if( rc != LDAP_SUCCESS ) {
965                         return rc;
966                 }
967
968                 if( uidval.bv_val ) {
969                         int     i, c, got1;
970                         char    *tmp;
971
972                         tmp = slap_sl_realloc( out->bv_val, out->bv_len 
973                                 + STRLENOF( "#" ) + uidval.bv_len + 1,
974                                 ctx );
975                         if( tmp == NULL ) {
976                                 ber_memfree_x( out->bv_val, ctx );
977                                 return LDAP_OTHER;
978                         }
979                         out->bv_val = tmp;
980                         out->bv_val[out->bv_len++] = '#';
981                         out->bv_val[out->bv_len++] = '\'';
982
983                         got1 = uidval.bv_len < sizeof("'0'B"); 
984                         for( i = 1; i < uidval.bv_len - 2; i++ ) {
985                                 c = uidval.bv_val[i];
986                                 switch(c) {
987                                         case '0':
988                                                 if( got1 ) out->bv_val[out->bv_len++] = c;
989                                                 break;
990                                         case '1':
991                                                 got1 = 1;
992                                                 out->bv_val[out->bv_len++] = c;
993                                                 break;
994                                 }
995                         }
996
997                         out->bv_val[out->bv_len++] = '\'';
998                         out->bv_val[out->bv_len++] = 'B';
999                         out->bv_val[out->bv_len] = '\0';
1000                 }
1001         }
1002
1003 #ifdef NEW_LOGGING
1004         LDAP_LOG( OPERATION, ARGS, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1005 #else
1006         Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1007 #endif
1008
1009         return LDAP_SUCCESS;
1010 }
1011
1012 static int
1013 uniqueMemberNormalize(
1014         slap_mask_t usage,
1015         Syntax *syntax,
1016         MatchingRule *mr,
1017         struct berval *val,
1018         struct berval *normalized,
1019         void *ctx )
1020 {
1021         struct berval out;
1022         int rc;
1023
1024         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ));
1025
1026         ber_dupbv_x( &out, val, ctx );
1027         if ( BER_BVISEMPTY( &out ) ) {
1028                 *normalized = out;
1029
1030         } else {
1031                 struct berval uid = BER_BVNULL;
1032
1033                 uid.bv_val = strrchr( out.bv_val, '#' );
1034                 if ( uid.bv_val ) {
1035                         uid.bv_val++;
1036                         uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1037
1038                         rc = bitStringValidate( NULL, &uid );
1039                         if ( rc == LDAP_SUCCESS ) {
1040                                 uid.bv_val[-1] = '\0';
1041                                 out.bv_len -= uid.bv_len + 1;
1042                         } else {
1043                                 uid.bv_val = NULL;
1044                         }
1045                 }
1046
1047                 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1048
1049                 if( rc != LDAP_SUCCESS ) {
1050                         slap_sl_free( out.bv_val, ctx );
1051                         return LDAP_INVALID_SYNTAX;
1052                 }
1053
1054                 if( uid.bv_val ) {
1055                         char    *tmp;
1056
1057                         tmp = ch_realloc( normalized->bv_val,
1058                                 normalized->bv_len + uid.bv_len
1059                                 + STRLENOF("#") + 1 );
1060                         if ( tmp == NULL ) {
1061                                 ber_memfree_x( normalized->bv_val, ctx );
1062                                 return LDAP_OTHER;
1063                         }
1064
1065                         normalized->bv_val = tmp;
1066
1067                         /* insert the separator */
1068                         normalized->bv_val[normalized->bv_len++] = '#';
1069
1070                         /* append the UID */
1071                         AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1072                                 uid.bv_val, uid.bv_len );
1073                         normalized->bv_len += uid.bv_len;
1074
1075                         /* terminate */
1076                         normalized->bv_val[normalized->bv_len] = '\0';
1077                 }
1078
1079                 slap_sl_free( out.bv_val, ctx );
1080         }
1081
1082         return LDAP_SUCCESS;
1083 }
1084
1085 static int
1086 uniqueMemberMatch(
1087         int *matchp,
1088         slap_mask_t flags,
1089         Syntax *syntax,
1090         MatchingRule *mr,
1091         struct berval *value,
1092         void *assertedValue )
1093 {
1094         int match;
1095         struct berval *asserted = (struct berval *) assertedValue;
1096         struct berval assertedDN = BER_BVNULL;
1097         struct berval assertedUID = BER_BVNULL;
1098         struct berval valueDN = BER_BVNULL;
1099         struct berval valueUID = BER_BVNULL;
1100
1101         if( asserted->bv_len != 0 ) {
1102                 assertedDN = *asserted;
1103
1104                 if( assertedDN.bv_val[assertedDN.bv_len-1] == 'B'
1105                         && assertedDN.bv_val[assertedDN.bv_len-2] == '\'' )
1106                 {
1107                         /* assume presence of optional UID */
1108                         assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1109
1110                         if( assertedUID.bv_val == NULL ||
1111                                 assertedUID.bv_val < assertedDN.bv_val ||
1112                                 ( assertedUID.bv_val > assertedDN.bv_val &&
1113                                         assertedUID.bv_val[-1] == '\\' ))
1114                         {
1115                                 return LDAP_INVALID_SYNTAX;
1116                         }
1117
1118                         assertedUID.bv_len = assertedDN.bv_len -
1119                                 (assertedUID.bv_val - assertedDN.bv_val);
1120                         assertedDN.bv_len -= assertedUID.bv_len;
1121
1122                         /* trim the separator */
1123                         assertedUID.bv_len--;
1124                         assertedUID.bv_val++;
1125                 }
1126         }
1127
1128         if( value->bv_len != 0 ) {
1129                 valueDN = *value;
1130
1131                 if( valueDN.bv_val[valueDN.bv_len-1] == 'B'
1132                         && valueDN.bv_val[valueDN.bv_len-2] == '\'' )
1133                 {
1134                         /* assume presence of optional UID */
1135                         valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1136
1137                         if( valueUID.bv_val == NULL ||
1138                                 valueUID.bv_val < valueDN.bv_val ||
1139                                 ( valueUID.bv_val > valueDN.bv_val &&
1140                                         valueUID.bv_val[-1] == '\\' ) )
1141                         {
1142                                 return LDAP_INVALID_SYNTAX;
1143                         }
1144
1145                         valueUID.bv_len = valueDN.bv_len -
1146                                 (valueUID.bv_val - valueDN.bv_val);
1147                         valueDN.bv_len -= valueUID.bv_len;
1148
1149                         /* trim the separator */
1150                         valueUID.bv_len--;
1151                         valueUID.bv_val++;
1152                 }
1153         }
1154
1155         if( valueUID.bv_len && assertedUID.bv_len ) {
1156                 match = valueUID.bv_len - assertedUID.bv_len;
1157                 if ( match ) {
1158                         *matchp = match;
1159                         return LDAP_SUCCESS;
1160                 }
1161
1162                 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1163                 if( match ) {
1164                         *matchp = match;
1165                         return LDAP_SUCCESS;
1166                 }
1167         }
1168
1169         return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1170 }
1171
1172 /*
1173  * Handling boolean syntax and matching is quite rigid.
1174  * A more flexible approach would be to allow a variety
1175  * of strings to be normalized and prettied into TRUE
1176  * and FALSE.
1177  */
1178 static int
1179 booleanValidate(
1180         Syntax *syntax,
1181         struct berval *in )
1182 {
1183         /* very unforgiving validation, requires no normalization
1184          * before simplistic matching
1185          */
1186
1187         if( in->bv_len == 4 ) {
1188                 if( bvmatch( in, &slap_true_bv ) ) {
1189                         return LDAP_SUCCESS;
1190                 }
1191         } else if( in->bv_len == 5 ) {
1192                 if( bvmatch( in, &slap_false_bv ) ) {
1193                         return LDAP_SUCCESS;
1194                 }
1195         }
1196
1197         return LDAP_INVALID_SYNTAX;
1198 }
1199
1200 static int
1201 booleanMatch(
1202         int *matchp,
1203         slap_mask_t flags,
1204         Syntax *syntax,
1205         MatchingRule *mr,
1206         struct berval *value,
1207         void *assertedValue )
1208 {
1209         /* simplistic matching allowed by rigid validation */
1210         struct berval *asserted = (struct berval *) assertedValue;
1211         *matchp = value->bv_len != asserted->bv_len;
1212         return LDAP_SUCCESS;
1213 }
1214
1215 /*-------------------------------------------------------------------
1216 LDAP/X.500 string syntax / matching rules have a few oddities.  This
1217 comment attempts to detail how slapd(8) treats them.
1218
1219 Summary:
1220   StringSyntax          X.500   LDAP    Matching/Comments
1221   DirectoryString       CHOICE  UTF8    i/e + ignore insignificant spaces
1222   PrintableString       subset  subset  i/e + ignore insignificant spaces
1223   PrintableString       subset  subset  i/e + ignore insignificant spaces
1224   NumericString         subset  subset  ignore all spaces
1225   IA5String                     ASCII   ASCII   i/e + ignore insignificant spaces
1226   TeletexString         T.61    T.61    i/e + ignore insignificant spaces
1227
1228   TelephoneNumber       subset  subset  i + ignore all spaces and "-"
1229
1230   See draft-ietf-ldapbis-strpro for details (once published).
1231
1232
1233 Directory String -
1234   In X.500(93), a directory string can be either a PrintableString,
1235   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1236   In later versions, more CHOICEs were added.  In all cases the string
1237   must be non-empty.
1238
1239   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1240   A directory string cannot be zero length.
1241
1242   For matching, there are both case ignore and exact rules.  Both
1243   also require that "insignificant" spaces be ignored.
1244         spaces before the first non-space are ignored;
1245         spaces after the last non-space are ignored;
1246         spaces after a space are ignored.
1247   Note: by these rules (and as clarified in X.520), a string of only
1248   spaces is to be treated as if held one space, not empty (which
1249   would be a syntax error).
1250
1251 NumericString
1252   In ASN.1, numeric string is just a string of digits and spaces
1253   and could be empty.  However, in X.500, all attribute values of
1254   numeric string carry a non-empty constraint.  For example:
1255
1256         internationalISDNNumber ATTRIBUTE ::= {
1257                 WITH SYNTAX InternationalISDNNumber
1258                 EQUALITY MATCHING RULE numericStringMatch
1259                 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1260                 ID id-at-internationalISDNNumber }
1261         InternationalISDNNumber ::=
1262             NumericString (SIZE(1..ub-international-isdn-number))
1263
1264   Unforunately, some assertion values are don't carry the same
1265   constraint (but its unclear how such an assertion could ever
1266   be true). In LDAP, there is one syntax (numericString) not two
1267   (numericString with constraint, numericString without constraint).
1268   This should be treated as numericString with non-empty constraint.
1269   Note that while someone may have no ISDN number, there are no ISDN
1270   numbers which are zero length.
1271
1272   In matching, spaces are ignored.
1273
1274 PrintableString
1275   In ASN.1, Printable string is just a string of printable characters
1276   and can be empty.  In X.500, semantics much like NumericString (see
1277   serialNumber for a like example) excepting uses insignificant space
1278   handling instead of ignore all spaces.  
1279
1280 IA5String
1281   Basically same as PrintableString.  There are no examples in X.500,
1282   but same logic applies.  So we require them to be non-empty as
1283   well.
1284
1285 -------------------------------------------------------------------*/
1286
1287 static int
1288 UTF8StringValidate(
1289         Syntax *syntax,
1290         struct berval *in )
1291 {
1292         ber_len_t count;
1293         int len;
1294         unsigned char *u = (unsigned char *)in->bv_val;
1295
1296         if( in->bv_len == 0 && syntax == slap_schema.si_syn_directoryString ) {
1297                 /* directory strings cannot be empty */
1298                 return LDAP_INVALID_SYNTAX;
1299         }
1300
1301         for( count = in->bv_len; count > 0; count-=len, u+=len ) {
1302                 /* get the length indicated by the first byte */
1303                 len = LDAP_UTF8_CHARLEN2( u, len );
1304
1305                 /* very basic checks */
1306                 switch( len ) {
1307                         case 6:
1308                                 if( (u[5] & 0xC0) != 0x80 ) {
1309                                         return LDAP_INVALID_SYNTAX;
1310                                 }
1311                         case 5:
1312                                 if( (u[4] & 0xC0) != 0x80 ) {
1313                                         return LDAP_INVALID_SYNTAX;
1314                                 }
1315                         case 4:
1316                                 if( (u[3] & 0xC0) != 0x80 ) {
1317                                         return LDAP_INVALID_SYNTAX;
1318                                 }
1319                         case 3:
1320                                 if( (u[2] & 0xC0 )!= 0x80 ) {
1321                                         return LDAP_INVALID_SYNTAX;
1322                                 }
1323                         case 2:
1324                                 if( (u[1] & 0xC0) != 0x80 ) {
1325                                         return LDAP_INVALID_SYNTAX;
1326                                 }
1327                         case 1:
1328                                 /* CHARLEN already validated it */
1329                                 break;
1330                         default:
1331                                 return LDAP_INVALID_SYNTAX;
1332                 }
1333
1334                 /* make sure len corresponds with the offset
1335                         to the next character */
1336                 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1337         }
1338
1339         if( count != 0 ) {
1340                 return LDAP_INVALID_SYNTAX;
1341         }
1342
1343         return LDAP_SUCCESS;
1344 }
1345
1346 static int
1347 UTF8StringNormalize(
1348         slap_mask_t use,
1349         Syntax *syntax,
1350         MatchingRule *mr,
1351         struct berval *val,
1352         struct berval *normalized,
1353         void *ctx )
1354 {
1355         struct berval tmp, nvalue;
1356         int flags;
1357         int i, wasspace;
1358
1359         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
1360
1361         if( val->bv_val == NULL ) {
1362                 /* assume we're dealing with a syntax (e.g., UTF8String)
1363                  * which allows empty strings
1364                  */
1365                 normalized->bv_len = 0;
1366                 normalized->bv_val = NULL;
1367                 return LDAP_SUCCESS;
1368         }
1369
1370         flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1371                 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1372         flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1373                 ? LDAP_UTF8_APPROX : 0;
1374
1375         val = UTF8bvnormalize( val, &tmp, flags, ctx );
1376         if( val == NULL ) {
1377                 return LDAP_OTHER;
1378         }
1379         
1380         /* collapse spaces (in place) */
1381         nvalue.bv_len = 0;
1382         nvalue.bv_val = tmp.bv_val;
1383
1384         wasspace=1; /* trim leading spaces */
1385         for( i=0; i<tmp.bv_len; i++) {
1386                 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1387                         if( wasspace++ == 0 ) {
1388                                 /* trim repeated spaces */
1389                                 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1390                         }
1391                 } else {
1392                         wasspace = 0;
1393                         nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1394                 }
1395         }
1396
1397         if( nvalue.bv_len ) {
1398                 if( wasspace ) {
1399                         /* last character was a space, trim it */
1400                         --nvalue.bv_len;
1401                 }
1402                 nvalue.bv_val[nvalue.bv_len] = '\0';
1403
1404         } else {
1405                 /* string of all spaces is treated as one space */
1406                 nvalue.bv_val[0] = ' ';
1407                 nvalue.bv_val[1] = '\0';
1408                 nvalue.bv_len = 1;
1409         }
1410
1411         *normalized = nvalue;
1412         return LDAP_SUCCESS;
1413 }
1414
1415 #if defined(SLAPD_APPROX_INITIALS)
1416 #       define SLAPD_APPROX_DELIMITER "._ "
1417 #       define SLAPD_APPROX_WORDLEN 2
1418 #else
1419 #       define SLAPD_APPROX_DELIMITER " "
1420 #       define SLAPD_APPROX_WORDLEN 1
1421 #endif
1422
1423 static int
1424 approxMatch(
1425         int *matchp,
1426         slap_mask_t flags,
1427         Syntax *syntax,
1428         MatchingRule *mr,
1429         struct berval *value,
1430         void *assertedValue )
1431 {
1432         struct berval *nval, *assertv;
1433         char *val, **values, **words, *c;
1434         int i, count, len, nextchunk=0, nextavail=0;
1435
1436         /* Yes, this is necessary */
1437         nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
1438         if( nval == NULL ) {
1439                 *matchp = 1;
1440                 return LDAP_SUCCESS;
1441         }
1442
1443         /* Yes, this is necessary */
1444         assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1445                 NULL, LDAP_UTF8_APPROX, NULL );
1446         if( assertv == NULL ) {
1447                 ber_bvfree( nval );
1448                 *matchp = 1;
1449                 return LDAP_SUCCESS;
1450         }
1451
1452         /* Isolate how many words there are */
1453         for ( c = nval->bv_val, count = 1; *c; c++ ) {
1454                 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1455                 if ( c == NULL ) break;
1456                 *c = '\0';
1457                 count++;
1458         }
1459
1460         /* Get a phonetic copy of each word */
1461         words = (char **)ch_malloc( count * sizeof(char *) );
1462         values = (char **)ch_malloc( count * sizeof(char *) );
1463         for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
1464                 words[i] = c;
1465                 values[i] = phonetic(c);
1466         }
1467
1468         /* Work through the asserted value's words, to see if at least some
1469            of the words are there, in the same order. */
1470         len = 0;
1471         while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1472                 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1473                 if( len == 0 ) {
1474                         nextchunk++;
1475                         continue;
1476                 }
1477 #if defined(SLAPD_APPROX_INITIALS)
1478                 else if( len == 1 ) {
1479                         /* Single letter words need to at least match one word's initial */
1480                         for( i=nextavail; i<count; i++ )
1481                                 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1482                                         nextavail=i+1;
1483                                         break;
1484                                 }
1485                 }
1486 #endif
1487                 else {
1488                         /* Isolate the next word in the asserted value and phonetic it */
1489                         assertv->bv_val[nextchunk+len] = '\0';
1490                         val = phonetic( assertv->bv_val + nextchunk );
1491
1492                         /* See if this phonetic chunk is in the remaining words of *value */
1493                         for( i=nextavail; i<count; i++ ){
1494                                 if( !strcmp( val, values[i] ) ){
1495                                         nextavail = i+1;
1496                                         break;
1497                                 }
1498                         }
1499                         ch_free( val );
1500                 }
1501
1502                 /* This chunk in the asserted value was NOT within the *value. */
1503                 if( i >= count ) {
1504                         nextavail=-1;
1505                         break;
1506                 }
1507
1508                 /* Go on to the next word in the asserted value */
1509                 nextchunk += len+1;
1510         }
1511
1512         /* If some of the words were seen, call it a match */
1513         if( nextavail > 0 ) {
1514                 *matchp = 0;
1515         }
1516         else {
1517                 *matchp = 1;
1518         }
1519
1520         /* Cleanup allocs */
1521         ber_bvfree( assertv );
1522         for( i=0; i<count; i++ ) {
1523                 ch_free( values[i] );
1524         }
1525         ch_free( values );
1526         ch_free( words );
1527         ber_bvfree( nval );
1528
1529         return LDAP_SUCCESS;
1530 }
1531
1532 static int 
1533 approxIndexer(
1534         slap_mask_t use,
1535         slap_mask_t flags,
1536         Syntax *syntax,
1537         MatchingRule *mr,
1538         struct berval *prefix,
1539         BerVarray values,
1540         BerVarray *keysp,
1541         void *ctx )
1542 {
1543         char *c;
1544         int i,j, len, wordcount, keycount=0;
1545         struct berval *newkeys;
1546         BerVarray keys=NULL;
1547
1548         for( j=0; values[j].bv_val != NULL; j++ ) {
1549                 struct berval val = BER_BVNULL;
1550                 /* Yes, this is necessary */
1551                 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
1552                 assert( val.bv_val != NULL );
1553
1554                 /* Isolate how many words there are. There will be a key for each */
1555                 for( wordcount = 0, c = val.bv_val; *c; c++) {
1556                         len = strcspn(c, SLAPD_APPROX_DELIMITER);
1557                         if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1558                         c+= len;
1559                         if (*c == '\0') break;
1560                         *c = '\0';
1561                 }
1562
1563                 /* Allocate/increase storage to account for new keys */
1564                 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
1565                         * sizeof(struct berval) );
1566                 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1567                 if( keys ) ch_free( keys );
1568                 keys = newkeys;
1569
1570                 /* Get a phonetic copy of each word */
1571                 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1572                         len = strlen( c );
1573                         if( len < SLAPD_APPROX_WORDLEN ) continue;
1574                         ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1575                         keycount++;
1576                         i++;
1577                 }
1578
1579                 ber_memfree( val.bv_val );
1580         }
1581         keys[keycount].bv_val = NULL;
1582         *keysp = keys;
1583
1584         return LDAP_SUCCESS;
1585 }
1586
1587 static int 
1588 approxFilter(
1589         slap_mask_t use,
1590         slap_mask_t flags,
1591         Syntax *syntax,
1592         MatchingRule *mr,
1593         struct berval *prefix,
1594         void * assertedValue,
1595         BerVarray *keysp,
1596         void *ctx )
1597 {
1598         char *c;
1599         int i, count, len;
1600         struct berval *val;
1601         BerVarray keys;
1602
1603         /* Yes, this is necessary */
1604         val = UTF8bvnormalize( ((struct berval *)assertedValue),
1605                 NULL, LDAP_UTF8_APPROX, NULL );
1606         if( val == NULL || val->bv_val == NULL ) {
1607                 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1608                 keys[0].bv_val = NULL;
1609                 *keysp = keys;
1610                 ber_bvfree( val );
1611                 return LDAP_SUCCESS;
1612         }
1613
1614         /* Isolate how many words there are. There will be a key for each */
1615         for( count = 0,c = val->bv_val; *c; c++) {
1616                 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1617                 if( len >= SLAPD_APPROX_WORDLEN ) count++;
1618                 c+= len;
1619                 if (*c == '\0') break;
1620                 *c = '\0';
1621         }
1622
1623         /* Allocate storage for new keys */
1624         keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1625
1626         /* Get a phonetic copy of each word */
1627         for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1628                 len = strlen(c);
1629                 if( len < SLAPD_APPROX_WORDLEN ) continue;
1630                 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1631                 i++;
1632         }
1633
1634         ber_bvfree( val );
1635
1636         keys[count].bv_val = NULL;
1637         *keysp = keys;
1638
1639         return LDAP_SUCCESS;
1640 }
1641
1642 /* Remove all spaces and '-' characters */
1643 static int
1644 telephoneNumberNormalize(
1645         slap_mask_t usage,
1646         Syntax *syntax,
1647         MatchingRule *mr,
1648         struct berval *val,
1649         struct berval *normalized,
1650         void *ctx )
1651 {
1652         char *p, *q;
1653
1654         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ));
1655
1656         /* validator should have refused an empty string */
1657         assert( val->bv_len );
1658
1659         q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
1660
1661         for( p = val->bv_val; *p; p++ ) {
1662                 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1663                         *q++ = *p;
1664                 }
1665         }
1666         *q = '\0';
1667
1668         normalized->bv_len = q - normalized->bv_val;
1669
1670         if( normalized->bv_len == 0 ) {
1671                 slap_sl_free( normalized->bv_val, ctx );
1672                 normalized->bv_val = NULL;
1673                 return LDAP_INVALID_SYNTAX;
1674         }
1675
1676         return LDAP_SUCCESS;
1677 }
1678
1679 static int
1680 numericoidValidate(
1681         Syntax *syntax,
1682         struct berval *in )
1683 {
1684         struct berval val = *in;
1685
1686         if( val.bv_len == 0 ) {
1687                 /* disallow empty strings */
1688                 return LDAP_INVALID_SYNTAX;
1689         }
1690
1691         while( OID_LEADCHAR( val.bv_val[0] ) ) {
1692                 if ( val.bv_len == 1 ) {
1693                         return LDAP_SUCCESS;
1694                 }
1695
1696                 if ( val.bv_val[0] == '0' ) {
1697                         break;
1698                 }
1699
1700                 val.bv_val++;
1701                 val.bv_len--;
1702
1703                 while ( OID_LEADCHAR( val.bv_val[0] )) {
1704                         val.bv_val++;
1705                         val.bv_len--;
1706
1707                         if ( val.bv_len == 0 ) {
1708                                 return LDAP_SUCCESS;
1709                         }
1710                 }
1711
1712                 if( !OID_SEPARATOR( val.bv_val[0] )) {
1713                         break;
1714                 }
1715
1716                 val.bv_val++;
1717                 val.bv_len--;
1718         }
1719
1720         return LDAP_INVALID_SYNTAX;
1721 }
1722
1723 static int
1724 integerValidate(
1725         Syntax *syntax,
1726         struct berval *in )
1727 {
1728         ber_len_t i;
1729         struct berval val = *in;
1730
1731         if( val.bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1732
1733         if ( val.bv_val[0] == '-' ) {
1734                 val.bv_len--;
1735                 val.bv_val++;
1736
1737                 if( val.bv_len == 0 ) { /* bare "-" */
1738                         return LDAP_INVALID_SYNTAX;
1739                 }
1740
1741                 if( val.bv_val[0] == '0' ) { /* "-0" */
1742                         return LDAP_INVALID_SYNTAX;
1743                 }
1744
1745         } else if ( val.bv_val[0] == '0' ) {
1746                 if( val.bv_len > 1 ) { /* "0<more>" */
1747                         return LDAP_INVALID_SYNTAX;
1748                 }
1749
1750                 return LDAP_SUCCESS;
1751         }
1752
1753         for( i=0; i < val.bv_len; i++ ) {
1754                 if( !ASCII_DIGIT(val.bv_val[i]) ) {
1755                         return LDAP_INVALID_SYNTAX;
1756                 }
1757         }
1758
1759         return LDAP_SUCCESS;
1760 }
1761
1762 static int
1763 integerMatch(
1764         int *matchp,
1765         slap_mask_t flags,
1766         Syntax *syntax,
1767         MatchingRule *mr,
1768         struct berval *value,
1769         void *assertedValue )
1770 {
1771         struct berval *asserted = (struct berval *) assertedValue;
1772         int vsign = 1, asign = 1;       /* default sign = '+' */
1773         struct berval v, a;
1774         int match;
1775
1776         v = *value;
1777         if( v.bv_val[0] == '-' ) {
1778                 vsign = -1;
1779                 v.bv_val++;
1780                 v.bv_len--;
1781         }
1782
1783         if( v.bv_len == 0 ) vsign = 0;
1784
1785         a = *asserted;
1786         if( a.bv_val[0] == '-' ) {
1787                 asign = -1;
1788                 a.bv_val++;
1789                 a.bv_len--;
1790         }
1791
1792         if( a.bv_len == 0 ) vsign = 0;
1793
1794         match = vsign - asign;
1795         if( match == 0 ) {
1796                 match = ( v.bv_len != a.bv_len
1797                         ? ( v.bv_len < a.bv_len ? -1 : 1 )
1798                         : memcmp( v.bv_val, a.bv_val, v.bv_len ));
1799                 if( vsign < 0 ) match = -match;
1800         }
1801
1802         *matchp = match;
1803         return LDAP_SUCCESS;
1804 }
1805         
1806 static int
1807 countryStringValidate(
1808         Syntax *syntax,
1809         struct berval *val )
1810 {
1811         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
1812
1813         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
1814                 return LDAP_INVALID_SYNTAX;
1815         }
1816         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
1817                 return LDAP_INVALID_SYNTAX;
1818         }
1819
1820         return LDAP_SUCCESS;
1821 }
1822
1823 static int
1824 printableStringValidate(
1825         Syntax *syntax,
1826         struct berval *val )
1827 {
1828         ber_len_t i;
1829
1830         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1831
1832         for(i=0; i < val->bv_len; i++) {
1833                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
1834                         return LDAP_INVALID_SYNTAX;
1835                 }
1836         }
1837
1838         return LDAP_SUCCESS;
1839 }
1840
1841 static int
1842 printablesStringValidate(
1843         Syntax *syntax,
1844         struct berval *val )
1845 {
1846         ber_len_t i, len;
1847
1848         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1849
1850         for(i=0,len=0; i < val->bv_len; i++) {
1851                 int c = val->bv_val[i];
1852
1853                 if( c == '$' ) {
1854                         if( len == 0 ) {
1855                                 return LDAP_INVALID_SYNTAX;
1856                         }
1857                         len = 0;
1858
1859                 } else if ( SLAP_PRINTABLE(c) ) {
1860                         len++;
1861                 } else {
1862                         return LDAP_INVALID_SYNTAX;
1863                 }
1864         }
1865
1866         if( len == 0 ) {
1867                 return LDAP_INVALID_SYNTAX;
1868         }
1869
1870         return LDAP_SUCCESS;
1871 }
1872
1873 static int
1874 IA5StringValidate(
1875         Syntax *syntax,
1876         struct berval *val )
1877 {
1878         ber_len_t i;
1879
1880         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1881
1882         for(i=0; i < val->bv_len; i++) {
1883                 if( !LDAP_ASCII(val->bv_val[i]) ) {
1884                         return LDAP_INVALID_SYNTAX;
1885                 }
1886         }
1887
1888         return LDAP_SUCCESS;
1889 }
1890
1891 static int
1892 IA5StringNormalize(
1893         slap_mask_t use,
1894         Syntax *syntax,
1895         MatchingRule *mr,
1896         struct berval *val,
1897         struct berval *normalized,
1898         void *ctx )
1899 {
1900         char *p, *q;
1901         int casefold = !SLAP_MR_ASSOCIATED(mr, slap_schema.si_mr_caseExactIA5Match);
1902
1903         assert( val->bv_len );
1904
1905         assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
1906
1907         p = val->bv_val;
1908
1909         /* Ignore initial whitespace */
1910         while ( ASCII_SPACE( *p ) ) p++;
1911
1912         normalized->bv_val = ber_strdup_x( p, ctx );
1913         p = q = normalized->bv_val;
1914
1915         while ( *p ) {
1916                 if ( ASCII_SPACE( *p ) ) {
1917                         *q++ = *p++;
1918
1919                         /* Ignore the extra whitespace */
1920                         while ( ASCII_SPACE( *p ) ) {
1921                                 p++;
1922                         }
1923
1924                 } else if ( casefold ) {
1925                         /* Most IA5 rules require casefolding */
1926                         *q++ = TOLOWER(*p); p++;
1927
1928                 } else {
1929                         *q++ = *p++;
1930                 }
1931         }
1932
1933         assert( normalized->bv_val <= p );
1934         assert( q <= p );
1935
1936         /*
1937          * If the string ended in space, backup the pointer one
1938          * position.  One is enough because the above loop collapsed
1939          * all whitespace to a single space.
1940          */
1941         if ( ASCII_SPACE( q[-1] ) ) --q;
1942
1943         /* null terminate */
1944         *q = '\0';
1945
1946         normalized->bv_len = q - normalized->bv_val;
1947         if( normalized->bv_len == 0 ) {
1948                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
1949                 normalized->bv_val[0] = ' ';
1950                 normalized->bv_val[1] = '\0';
1951                 normalized->bv_len = 1;
1952         }
1953
1954         return LDAP_SUCCESS;
1955 }
1956
1957 static int
1958 UUIDValidate(
1959         Syntax *syntax,
1960         struct berval *in )
1961 {
1962         int i;
1963         if( in->bv_len != 36 ) {
1964                 assert(0);
1965                 return LDAP_INVALID_SYNTAX;
1966         }
1967
1968         for( i=0; i<36; i++ ) {
1969                 switch(i) {
1970                         case 8:
1971                         case 13:
1972                         case 18:
1973                         case 23:
1974                                 if( in->bv_val[i] != '-' ) {
1975                                         return LDAP_INVALID_SYNTAX;
1976                                 }
1977                                 break;
1978                         default:
1979                                 if( !ASCII_HEX( in->bv_val[i]) ) {
1980                                         return LDAP_INVALID_SYNTAX;
1981                                 }
1982                 }
1983         }
1984         
1985         return LDAP_SUCCESS;
1986 }
1987
1988 static int
1989 UUIDNormalize(
1990         slap_mask_t usage,
1991         Syntax *syntax,
1992         MatchingRule *mr,
1993         struct berval *val,
1994         struct berval *normalized,
1995         void *ctx )
1996 {
1997         unsigned char octet = '\0';
1998         int i;
1999         int j;
2000         normalized->bv_len = 16;
2001         normalized->bv_val = slap_sl_malloc( normalized->bv_len+1, ctx );
2002
2003         for( i=0, j=0; i<36; i++ ) {
2004                 unsigned char nibble;
2005                 if( val->bv_val[i] == '-' ) {
2006                         continue;
2007
2008                 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2009                         nibble = val->bv_val[i] - '0';
2010
2011                 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2012                         nibble = val->bv_val[i] - ('a'-10);
2013
2014                 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2015                         nibble = val->bv_val[i] - ('A'-10);
2016
2017                 } else {
2018                         slap_sl_free( normalized->bv_val, ctx );
2019                         return LDAP_INVALID_SYNTAX;
2020                 }
2021
2022                 if( j & 1 ) {
2023                         octet |= nibble;
2024                         normalized->bv_val[j>>1] = octet;
2025                 } else {
2026                         octet = nibble << 4;
2027                 }
2028                 j++;
2029         }
2030
2031         normalized->bv_val[normalized->bv_len] = 0;
2032         return LDAP_SUCCESS;
2033 }
2034
2035
2036
2037 static int
2038 numericStringValidate(
2039         Syntax *syntax,
2040         struct berval *in )
2041 {
2042         ber_len_t i;
2043
2044         if( in->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
2045
2046         for(i=0; i < in->bv_len; i++) {
2047                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2048                         return LDAP_INVALID_SYNTAX;
2049                 }
2050         }
2051
2052         return LDAP_SUCCESS;
2053 }
2054
2055 static int
2056 numericStringNormalize(
2057         slap_mask_t usage,
2058         Syntax *syntax,
2059         MatchingRule *mr,
2060         struct berval *val,
2061         struct berval *normalized,
2062         void *ctx )
2063 {
2064         /* removal all spaces */
2065         char *p, *q;
2066
2067         assert( val->bv_len );
2068
2069         normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2070
2071         p = val->bv_val;
2072         q = normalized->bv_val;
2073
2074         while ( *p ) {
2075                 if ( ASCII_SPACE( *p ) ) {
2076                         /* Ignore whitespace */
2077                         p++;
2078                 } else {
2079                         *q++ = *p++;
2080                 }
2081         }
2082
2083         /* we should have copied no more then is in val */
2084         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2085
2086         /* null terminate */
2087         *q = '\0';
2088
2089         normalized->bv_len = q - normalized->bv_val;
2090
2091         if( normalized->bv_len == 0 ) {
2092                 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2093                 normalized->bv_val[0] = ' ';
2094                 normalized->bv_val[1] = '\0';
2095                 normalized->bv_len = 1;
2096         }
2097
2098         return LDAP_SUCCESS;
2099 }
2100
2101 /*
2102  * Integer conversion macros that will use the largest available
2103  * type.
2104  */
2105 #if defined(HAVE_STRTOLL) && defined(LLONG_MAX) \
2106         && defined(LLONG_MIN) && defined(HAVE_LONG_LONG)
2107 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
2108 # define SLAP_LONG_MAX       LLONG_MAX
2109 # define SLAP_LONG_MIN       LLONG_MIN
2110 # define SLAP_LONG           long long
2111 #else
2112 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
2113 # define SLAP_LONG_MAX       LONG_MAX
2114 # define SLAP_LONG_MIN       LONG_MIN
2115 # define SLAP_LONG           long
2116 #endif /* HAVE_STRTOLL ... */
2117
2118 static int
2119 integerBitAndMatch(
2120         int *matchp,
2121         slap_mask_t flags,
2122         Syntax *syntax,
2123         MatchingRule *mr,
2124         struct berval *value,
2125         void *assertedValue )
2126 {
2127         SLAP_LONG lValue, lAssertedValue;
2128
2129         /* safe to assume integers are NUL terminated? */
2130         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2131         if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX) &&
2132                 errno == ERANGE )
2133         {
2134                 return LDAP_CONSTRAINT_VIOLATION;
2135         }
2136
2137         lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2138                 NULL, 10);
2139         if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX ) &&
2140                 errno == ERANGE )
2141         {
2142                 return LDAP_CONSTRAINT_VIOLATION;
2143         }
2144
2145         *matchp = (lValue & lAssertedValue) ? 0 : 1;
2146         return LDAP_SUCCESS;
2147 }
2148
2149 static int
2150 integerBitOrMatch(
2151         int *matchp,
2152         slap_mask_t flags,
2153         Syntax *syntax,
2154         MatchingRule *mr,
2155         struct berval *value,
2156         void *assertedValue )
2157 {
2158         SLAP_LONG lValue, lAssertedValue;
2159
2160         /* safe to assume integers are NUL terminated? */
2161         lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2162         if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX ) &&
2163                 errno == ERANGE )
2164         {
2165                 return LDAP_CONSTRAINT_VIOLATION;
2166         }
2167
2168         lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2169                 NULL, 10);
2170         if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX ) &&
2171                 errno == ERANGE )
2172         {
2173                 return LDAP_CONSTRAINT_VIOLATION;
2174         }
2175
2176         *matchp = (lValue | lAssertedValue) ? 0 : -1;
2177         return LDAP_SUCCESS;
2178 }
2179
2180 static int
2181 serialNumberAndIssuerValidate(
2182         Syntax *syntax,
2183         struct berval *in )
2184 {
2185         int rc;
2186         int state;
2187         ber_len_t n;
2188         struct berval sn, i;
2189         if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2190
2191         i.bv_val = strchr( in->bv_val, '$' );
2192         if( i.bv_val == NULL ) return LDAP_INVALID_SYNTAX;
2193
2194         sn.bv_val = in->bv_val;
2195         sn.bv_len = i.bv_val - in->bv_val;
2196
2197         i.bv_val++;
2198         i.bv_len = in->bv_len - (sn.bv_len + 1);
2199
2200         /* validate serial number (strict for now) */
2201         for( n=0; n < sn.bv_len; n++ ) {
2202                 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2203         }
2204
2205         /* validate DN */
2206         rc = dnValidate( NULL, &i );
2207         if( rc ) return LDAP_INVALID_SYNTAX;
2208
2209         return LDAP_SUCCESS;
2210 }
2211
2212 int
2213 serialNumberAndIssuerPretty(
2214         Syntax *syntax,
2215         struct berval *val,
2216         struct berval *out,
2217         void *ctx )
2218 {
2219         int rc;
2220         int state;
2221         ber_len_t n;
2222         struct berval sn, i, newi;
2223
2224         assert( val );
2225         assert( out );
2226
2227 #ifdef NEW_LOGGING
2228         LDAP_LOG( OPERATION, ARGS, ">>> serialNumberAndIssuerPretty: <%s>\n",
2229                 val->bv_val, 0, 0 );
2230 #else
2231         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
2232                 val->bv_val, 0, 0 );
2233 #endif
2234
2235         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2236
2237         i.bv_val = strchr( val->bv_val, '$' );
2238         if( i.bv_val == NULL ) return LDAP_INVALID_SYNTAX;
2239
2240         sn.bv_val = val->bv_val;
2241         sn.bv_len = i.bv_val - val->bv_val;
2242
2243         i.bv_val++;
2244         i.bv_len = val->bv_len - (sn.bv_len + 1);
2245
2246         /* eat leading zeros */
2247         for( n=0; n < (sn.bv_len-1); n++ ) {
2248                 if( sn.bv_val[n] != '0' ) break;
2249         }
2250         sn.bv_val += n;
2251         sn.bv_len -= n;
2252
2253         for( n=0; n < sn.bv_len; n++ ) {
2254                 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2255         }
2256
2257         /* pretty DN */
2258         rc = dnPretty( syntax, &i, &newi, ctx );
2259         if( rc ) return LDAP_INVALID_SYNTAX;
2260
2261         /* make room from sn + "$" */
2262         out->bv_len = sn.bv_len + newi.bv_len + 1;
2263         out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2264
2265         if( out->bv_val == NULL ) {
2266                 slap_sl_free( newi.bv_val, ctx );
2267                 return LDAP_OTHER;
2268         }
2269
2270         /* push issuer over */
2271         AC_MEMCPY( &out->bv_val[sn.bv_len+1], newi.bv_val, newi.bv_len );
2272         /* insert sn and "$" */
2273         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2274         out->bv_val[sn.bv_len] = '$';
2275         /* terminate */
2276         out->bv_val[out->bv_len] = '\0';
2277
2278 #ifdef NEW_LOGGING
2279         LDAP_LOG( OPERATION, ARGS, "<<< serialNumberAndIssuerPretty: <%s>\n",
2280                 out->bv_val, 0, 0 );
2281 #else
2282         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
2283                 out->bv_val, 0, 0 );
2284 #endif
2285
2286         return LDAP_SUCCESS;
2287 }
2288
2289 /*
2290  * This routine is called by certificateExactNormalize when
2291  * certificateExactNormalize receives a search string instead of
2292  * a certificate. This routine checks if the search value is valid
2293  * and then returns the normalized value
2294  */
2295 static int
2296 serialNumberAndIssuerNormalize(
2297         slap_mask_t usage,
2298         Syntax *syntax,
2299         MatchingRule *mr,
2300         struct berval *val,
2301         struct berval *out,
2302         void *ctx )
2303 {
2304         int rc;
2305         int state;
2306         ber_len_t n;
2307         struct berval sn, i, newi;
2308
2309         assert( val );
2310         assert( out );
2311
2312 #ifdef NEW_LOGGING
2313         LDAP_LOG( OPERATION, ARGS, ">>> serialNumberAndIssuerNormalize: <%s>\n",
2314                 val->bv_val, 0, 0 );
2315 #else
2316         Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
2317                 val->bv_val, 0, 0 );
2318 #endif
2319
2320         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2321
2322         i.bv_val = strchr( val->bv_val, '$' );
2323         if( i.bv_val == NULL ) return LDAP_INVALID_SYNTAX;
2324
2325         sn.bv_val = val->bv_val;
2326         sn.bv_len = i.bv_val - val->bv_val;
2327
2328         i.bv_val++;
2329         i.bv_len = val->bv_len - (sn.bv_len + 1);
2330
2331         /* eat leading zeros */
2332         for( n=0; n < (sn.bv_len-1); n++ ) {
2333                 if( sn.bv_val[n] != '0' ) break;
2334         }
2335         sn.bv_val += n;
2336         sn.bv_len -= n;
2337
2338         for( n=0; n < sn.bv_len; n++ ) {
2339                 if( !ASCII_DIGIT(sn.bv_val[n]) ) {
2340                         return LDAP_INVALID_SYNTAX;
2341                 }
2342         }
2343
2344         /* pretty DN */
2345         rc = dnNormalize( usage, syntax, mr, &i, &newi, ctx );
2346         if( rc ) return LDAP_INVALID_SYNTAX;
2347
2348         /* make room from sn + "$" */
2349         out->bv_len = sn.bv_len + newi.bv_len + 1;
2350         out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2351
2352         if( out->bv_val == NULL ) {
2353                 slap_sl_free( newi.bv_val, ctx );
2354                 return LDAP_OTHER;
2355         }
2356
2357         /* push issuer over */
2358         AC_MEMCPY( &out->bv_val[sn.bv_len+1], newi.bv_val, newi.bv_len );
2359         /* insert sn and "$" */
2360         AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2361         out->bv_val[sn.bv_len] = '$';
2362         /* terminate */
2363         out->bv_val[out->bv_len] = '\0';
2364
2365 #ifdef NEW_LOGGING
2366         LDAP_LOG( OPERATION, ARGS, "<<< serialNumberAndIssuerNormalize: <%s>\n",
2367                 out->bv_val, 0, 0 );
2368 #else
2369         Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
2370                 out->bv_val, 0, 0 );
2371 #endif
2372
2373         return rc;
2374 }
2375
2376 #ifdef HAVE_TLS
2377 static int
2378 certificateExactNormalize(
2379         slap_mask_t usage,
2380         Syntax *syntax,
2381         MatchingRule *mr,
2382         struct berval *val,
2383         struct berval *normalized,
2384         void *ctx )
2385 {
2386         int rc = LDAP_INVALID_SYNTAX;
2387         unsigned char *p;
2388         char *serial = NULL;
2389         ber_len_t seriallen;
2390         struct berval issuer_dn = BER_BVNULL;
2391         X509_NAME *name = NULL;
2392         ASN1_INTEGER *sn = NULL;
2393         X509 *xcert = NULL;
2394
2395         if( val->bv_len == 0 ) goto done;
2396
2397         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
2398                 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
2399         }
2400
2401         assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) );
2402
2403         p = (unsigned char *)val->bv_val;
2404         xcert = d2i_X509( NULL, &p, val->bv_len);
2405         if( xcert == NULL ) goto done;
2406
2407         sn=X509_get_serialNumber(xcert);
2408         if ( sn == NULL ) goto done;
2409         serial=i2s_ASN1_INTEGER(0, sn );
2410         if( serial == NULL ) goto done;
2411         seriallen=strlen(serial);
2412
2413         name=X509_get_issuer_name(xcert);
2414         if( name == NULL ) goto done;
2415         rc = dnX509normalize( name, &issuer_dn );
2416         if( rc != LDAP_SUCCESS ) goto done;
2417
2418         normalized->bv_len = seriallen + issuer_dn.bv_len + 1;
2419         normalized->bv_val = ch_malloc(normalized->bv_len+1);
2420         p = (unsigned char *)normalized->bv_val;
2421         AC_MEMCPY(p, serial, seriallen);
2422         p += seriallen;
2423         *p++ = '$';
2424         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
2425         p += issuer_dn.bv_len;
2426         *p = '\0';
2427
2428 #ifdef NEW_LOGGING
2429         LDAP_LOG( CONFIG, ARGS, "certificateExactNormalize: %s\n",
2430                 normalized->bv_val, 0, 0 );
2431 #else
2432         Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
2433                 normalized->bv_val, NULL, NULL );
2434 #endif
2435
2436 done:
2437         if (xcert) X509_free(xcert);
2438         if (serial) ch_free(serial);
2439         if (issuer_dn.bv_val) ber_memfree(issuer_dn.bv_val);
2440
2441         return rc;
2442 }
2443 #endif /* HAVE_TLS */
2444
2445
2446 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
2447 /* slight optimization - does not need the start parameter */
2448 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
2449 enum { start = 0 };
2450 #endif
2451
2452 static int
2453 check_time_syntax (struct berval *val,
2454         int start,
2455         int *parts,
2456         struct berval *fraction)
2457 {
2458         /*
2459          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
2460          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
2461          * GeneralizedTime supports leap seconds, UTCTime does not.
2462          */
2463         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
2464         static const int mdays[2][12] = {
2465                 /* non-leap years */
2466                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
2467                 /* leap years */
2468                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
2469         };
2470         char *p, *e;
2471         int part, c, c1, c2, tzoffset, leapyear = 0;
2472
2473         p = val->bv_val;
2474         e = p + val->bv_len;
2475
2476 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2477         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
2478 #endif
2479         for (part = start; part < 7 && p < e; part++) {
2480                 c1 = *p;
2481                 if (!ASCII_DIGIT(c1)) {
2482                         break;
2483                 }
2484                 p++;
2485                 if (p == e) {
2486                         return LDAP_INVALID_SYNTAX;
2487                 }
2488                 c = *p++;
2489                 if (!ASCII_DIGIT(c)) {
2490                         return LDAP_INVALID_SYNTAX;
2491                 }
2492                 c += c1 * 10 - '0' * 11;
2493                 if ((part | 1) == 3) {
2494                         --c;
2495                         if (c < 0) {
2496                                 return LDAP_INVALID_SYNTAX;
2497                         }
2498                 }
2499                 if (c >= ceiling[part]) {
2500                         if (! (c == 60 && part == 6 && start == 0))
2501                                 return LDAP_INVALID_SYNTAX;
2502                 }
2503                 parts[part] = c;
2504         }
2505         if (part < 5 + start) {
2506                 return LDAP_INVALID_SYNTAX;
2507         }
2508         for (; part < 9; part++) {
2509                 parts[part] = 0;
2510         }
2511
2512         /* leapyear check for the Gregorian calendar (year>1581) */
2513         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0)
2514         {
2515                 leapyear = 1;
2516         }
2517
2518         if (parts[3] >= mdays[leapyear][parts[2]]) {
2519                 return LDAP_INVALID_SYNTAX;
2520         }
2521
2522         if (start == 0) {
2523                 fraction->bv_val = p;
2524                 fraction->bv_len = 0;
2525                 if (p < e && (*p == '.' || *p == ',')) {
2526                         char *end_num;
2527                         while (++p < e && ASCII_DIGIT(*p))
2528                                 ;
2529                         if (p - fraction->bv_val == 1) {
2530                                 return LDAP_INVALID_SYNTAX;
2531                         }
2532                         for (end_num = p; end_num[-1] == '0'; --end_num)
2533                                 ;
2534                         c = end_num - fraction->bv_val;
2535                         if (c != 1)
2536                                 fraction->bv_len = c;
2537                 }
2538         }
2539
2540         if (p == e) {
2541                 /* no time zone */
2542                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2543         }
2544
2545         tzoffset = *p++;
2546         switch (tzoffset) {
2547         default:
2548                 return LDAP_INVALID_SYNTAX;
2549         case 'Z':
2550                 /* UTC */
2551                 break;
2552         case '+':
2553         case '-':
2554                 for (part = 7; part < 9 && p < e; part++) {
2555                         c1 = *p;
2556                         if (!ASCII_DIGIT(c1)) {
2557                                 break;
2558                         }
2559                         p++;
2560                         if (p == e) {
2561                                 return LDAP_INVALID_SYNTAX;
2562                         }
2563                         c2 = *p++;
2564                         if (!ASCII_DIGIT(c2)) {
2565                                 return LDAP_INVALID_SYNTAX;
2566                         }
2567                         parts[part] = c1 * 10 + c2 - '0' * 11;
2568                         if (parts[part] >= ceiling[part]) {
2569                                 return LDAP_INVALID_SYNTAX;
2570                         }
2571                 }
2572                 if (part < 8 + start) {
2573                         return LDAP_INVALID_SYNTAX;
2574                 }
2575
2576                 if (tzoffset == '-') {
2577                         /* negative offset to UTC, ie west of Greenwich */
2578                         parts[4] += parts[7];
2579                         parts[5] += parts[8];
2580                         /* offset is just hhmm, no seconds */
2581                         for (part = 6; --part >= 0; ) {
2582                                 if (part != 3) {
2583                                         c = ceiling[part];
2584                                 } else {
2585                                         c = mdays[leapyear][parts[2]];
2586                                 }
2587                                 if (parts[part] >= c) {
2588                                         if (part == 0) {
2589                                                 return LDAP_INVALID_SYNTAX;
2590                                         }
2591                                         parts[part] -= c;
2592                                         parts[part - 1]++;
2593                                         continue;
2594                                 } else if (part != 5) {
2595                                         break;
2596                                 }
2597                         }
2598                 } else {
2599                         /* positive offset to UTC, ie east of Greenwich */
2600                         parts[4] -= parts[7];
2601                         parts[5] -= parts[8];
2602                         for (part = 6; --part >= 0; ) {
2603                                 if (parts[part] < 0) {
2604                                         if (part == 0) {
2605                                                 return LDAP_INVALID_SYNTAX;
2606                                         }
2607                                         if (part != 3) {
2608                                                 c = ceiling[part];
2609                                         } else {
2610                                                 /* make first arg to % non-negative */
2611                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
2612                                         }
2613                                         parts[part] += c;
2614                                         parts[part - 1]--;
2615                                         continue;
2616                                 } else if (part != 5) {
2617                                         break;
2618                                 }
2619                         }
2620                 }
2621         }
2622
2623         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2624 }
2625
2626 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2627
2628 #if 0
2629 static int
2630 xutcTimeNormalize(
2631         Syntax *syntax,
2632         struct berval *val,
2633         struct berval *normalized )
2634 {
2635         int parts[9], rc;
2636
2637         rc = check_time_syntax(val, 1, parts, NULL);
2638         if (rc != LDAP_SUCCESS) {
2639                 return rc;
2640         }
2641
2642         normalized->bv_val = ch_malloc( 14 );
2643         if ( normalized->bv_val == NULL ) {
2644                 return LBER_ERROR_MEMORY;
2645         }
2646
2647         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
2648                 parts[1], parts[2] + 1, parts[3] + 1,
2649                 parts[4], parts[5], parts[6] );
2650         normalized->bv_len = 13;
2651
2652         return LDAP_SUCCESS;
2653 }
2654 #endif /* 0 */
2655
2656 static int
2657 utcTimeValidate(
2658         Syntax *syntax,
2659         struct berval *in )
2660 {
2661         int parts[9];
2662         return check_time_syntax(in, 1, parts, NULL);
2663 }
2664
2665 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
2666
2667 static int
2668 generalizedTimeValidate(
2669         Syntax *syntax,
2670         struct berval *in )
2671 {
2672         int parts[9];
2673         struct berval fraction;
2674         return check_time_syntax(in, 0, parts, &fraction);
2675 }
2676
2677 static int
2678 generalizedTimeNormalize(
2679         slap_mask_t usage,
2680         Syntax *syntax,
2681         MatchingRule *mr,
2682         struct berval *val,
2683         struct berval *normalized,
2684         void *ctx )
2685 {
2686         int parts[9], rc;
2687         unsigned int len;
2688         struct berval fraction;
2689
2690         rc = check_time_syntax(val, 0, parts, &fraction);
2691         if (rc != LDAP_SUCCESS) {
2692                 return rc;
2693         }
2694
2695         len = sizeof("YYYYmmddHHMMSSZ")-1 + fraction.bv_len;
2696         normalized->bv_val = slap_sl_malloc( len + 1, ctx );
2697         if ( normalized->bv_val == NULL ) {
2698                 return LBER_ERROR_MEMORY;
2699         }
2700
2701         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
2702                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
2703                 parts[4], parts[5], parts[6] );
2704         if ( fraction.bv_len ) {
2705                 memcpy( normalized->bv_val + sizeof("YYYYmmddHHMMSSZ")-2,
2706                         fraction.bv_val, fraction.bv_len );
2707                 normalized->bv_val[sizeof("YYYYmmddHHMMSSZ")-2] = '.';
2708         }
2709         strcpy( normalized->bv_val + len-1, "Z" );
2710         normalized->bv_len = len;
2711
2712         return LDAP_SUCCESS;
2713 }
2714
2715 static int
2716 generalizedTimeOrderingMatch(
2717         int *matchp,
2718         slap_mask_t flags,
2719         Syntax *syntax,
2720         MatchingRule *mr,
2721         struct berval *value,
2722         void *assertedValue )
2723 {
2724         struct berval *asserted = (struct berval *) assertedValue;
2725         ber_len_t v_len  = value->bv_len;
2726         ber_len_t av_len = asserted->bv_len;
2727
2728         /* ignore trailing 'Z' when comparing */
2729         int match = memcmp( value->bv_val, asserted->bv_val,
2730                 (v_len < av_len ? v_len : av_len) - 1 );
2731         if ( match == 0 ) match = v_len - av_len;
2732
2733         *matchp = match;
2734         return LDAP_SUCCESS;
2735 }
2736
2737 static int
2738 deliveryMethodValidate(
2739         Syntax *syntax,
2740         struct berval *val )
2741 {
2742 #undef LENOF
2743 #define LENOF(s) (sizeof(s)-1)
2744         struct berval tmp = *val;
2745         /*
2746      *  DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
2747          *      pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
2748          *              "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
2749          */
2750 again:
2751         if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2752
2753         switch( tmp.bv_val[0] ) {
2754         case 'a':
2755         case 'A':
2756                 if(( tmp.bv_len >= LENOF("any") ) &&
2757                         ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
2758                 {
2759                         tmp.bv_len -= LENOF("any");
2760                         tmp.bv_val += LENOF("any");
2761                         break;
2762                 }
2763                 return LDAP_INVALID_SYNTAX;
2764
2765         case 'm':
2766         case 'M':
2767                 if(( tmp.bv_len >= LENOF("mhs") ) &&
2768                         ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
2769                 {
2770                         tmp.bv_len -= LENOF("mhs");
2771                         tmp.bv_val += LENOF("mhs");
2772                         break;
2773                 }
2774                 return LDAP_INVALID_SYNTAX;
2775
2776         case 'p':
2777         case 'P':
2778                 if(( tmp.bv_len >= LENOF("physical") ) &&
2779                         ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
2780                 {
2781                         tmp.bv_len -= LENOF("physical");
2782                         tmp.bv_val += LENOF("physical");
2783                         break;
2784                 }
2785                 return LDAP_INVALID_SYNTAX;
2786
2787         case 't':
2788         case 'T': /* telex or teletex or telephone */
2789                 if(( tmp.bv_len >= LENOF("telex") ) &&
2790                         ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
2791                 {
2792                         tmp.bv_len -= LENOF("telex");
2793                         tmp.bv_val += LENOF("telex");
2794                         break;
2795                 }
2796                 if(( tmp.bv_len >= LENOF("teletex") ) &&
2797                         ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
2798                 {
2799                         tmp.bv_len -= LENOF("teletex");
2800                         tmp.bv_val += LENOF("teletex");
2801                         break;
2802                 }
2803                 if(( tmp.bv_len >= LENOF("telephone") ) &&
2804                         ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
2805                 {
2806                         tmp.bv_len -= LENOF("telephone");
2807                         tmp.bv_val += LENOF("telephone");
2808                         break;
2809                 }
2810                 return LDAP_INVALID_SYNTAX;
2811
2812         case 'g':
2813         case 'G': /* g3fax or g4fax */
2814                 if(( tmp.bv_len >= LENOF("g3fax") ) && (
2815                         ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
2816                         ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
2817                 {
2818                         tmp.bv_len -= LENOF("g3fax");
2819                         tmp.bv_val += LENOF("g3fax");
2820                         break;
2821                 }
2822                 return LDAP_INVALID_SYNTAX;
2823
2824         case 'i':
2825         case 'I':
2826                 if(( tmp.bv_len >= LENOF("ia5") ) &&
2827                         ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
2828                 {
2829                         tmp.bv_len -= LENOF("ia5");
2830                         tmp.bv_val += LENOF("ia5");
2831                         break;
2832                 }
2833                 return LDAP_INVALID_SYNTAX;
2834
2835         case 'v':
2836         case 'V':
2837                 if(( tmp.bv_len >= LENOF("videotex") ) &&
2838                         ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
2839                 {
2840                         tmp.bv_len -= LENOF("videotex");
2841                         tmp.bv_val += LENOF("videotex");
2842                         break;
2843                 }
2844                 return LDAP_INVALID_SYNTAX;
2845
2846         default:
2847                 return LDAP_INVALID_SYNTAX;
2848         }
2849
2850         if( tmp.bv_len == 0 ) return LDAP_SUCCESS;
2851
2852         while( tmp.bv_len && ( tmp.bv_val[0] == ' ' )) {
2853                 tmp.bv_len++;
2854                 tmp.bv_val--;
2855         }
2856         if( tmp.bv_len && ( tmp.bv_val[0] == '$' )) {
2857                 tmp.bv_len++;
2858                 tmp.bv_val--;
2859         } else {
2860                 return LDAP_INVALID_SYNTAX;
2861         }
2862         while( tmp.bv_len && ( tmp.bv_val[0] == ' ' )) {
2863                 tmp.bv_len++;
2864                 tmp.bv_val--;
2865         }
2866
2867         goto again;
2868 }
2869
2870 static int
2871 nisNetgroupTripleValidate(
2872         Syntax *syntax,
2873         struct berval *val )
2874 {
2875         char *p, *e;
2876         int commas = 0;
2877
2878         if ( val->bv_len == 0 ) {
2879                 return LDAP_INVALID_SYNTAX;
2880         }
2881
2882         p = (char *)val->bv_val;
2883         e = p + val->bv_len;
2884
2885         if ( *p != '(' /*')'*/ ) {
2886                 return LDAP_INVALID_SYNTAX;
2887         }
2888
2889         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
2890                 if ( *p == ',' ) {
2891                         commas++;
2892                         if ( commas > 2 ) {
2893                                 return LDAP_INVALID_SYNTAX;
2894                         }
2895
2896                 } else if ( !AD_CHAR( *p ) ) {
2897                         return LDAP_INVALID_SYNTAX;
2898                 }
2899         }
2900
2901         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
2902                 return LDAP_INVALID_SYNTAX;
2903         }
2904
2905         p++;
2906
2907         if (p != e) {
2908                 return LDAP_INVALID_SYNTAX;
2909         }
2910
2911         return LDAP_SUCCESS;
2912 }
2913
2914 static int
2915 bootParameterValidate(
2916         Syntax *syntax,
2917         struct berval *val )
2918 {
2919         char *p, *e;
2920
2921         if ( val->bv_len == 0 ) {
2922                 return LDAP_INVALID_SYNTAX;
2923         }
2924
2925         p = (char *)val->bv_val;
2926         e = p + val->bv_len;
2927
2928         /* key */
2929         for (; ( p < e ) && ( *p != '=' ); p++ ) {
2930                 if ( !AD_CHAR( *p ) ) {
2931                         return LDAP_INVALID_SYNTAX;
2932                 }
2933         }
2934
2935         if ( *p != '=' ) {
2936                 return LDAP_INVALID_SYNTAX;
2937         }
2938
2939         /* server */
2940         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
2941                 if ( !AD_CHAR( *p ) ) {
2942                         return LDAP_INVALID_SYNTAX;
2943                 }
2944         }
2945
2946         if ( *p != ':' ) {
2947                 return LDAP_INVALID_SYNTAX;
2948         }
2949
2950         /* path */
2951         for ( p++; p < e; p++ ) {
2952                 if ( !SLAP_PRINTABLE( *p ) ) {
2953                         return LDAP_INVALID_SYNTAX;
2954                 }
2955         }
2956
2957         return LDAP_SUCCESS;
2958 }
2959
2960 static int
2961 firstComponentNormalize(
2962         slap_mask_t usage,
2963         Syntax *syntax,
2964         MatchingRule *mr,
2965         struct berval *val,
2966         struct berval *normalized,
2967         void *ctx )
2968 {
2969         int rc;
2970         struct berval comp;
2971         ber_len_t len;
2972
2973         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
2974                 ber_dupbv_x( normalized, val, ctx );
2975                 return LDAP_SUCCESS;
2976         }
2977
2978         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2979
2980         if( val->bv_val[0] != '(' /*')'*/ &&
2981                 val->bv_val[0] != '{' /*'}'*/ )
2982         {
2983                 return LDAP_INVALID_SYNTAX;
2984         }
2985
2986         /* trim leading white space */
2987         for( len=1;
2988                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
2989                 len++ )
2990         {
2991                 /* empty */
2992         }
2993
2994         /* grab next word */
2995         comp.bv_val = &val->bv_val[len];
2996         len = val->bv_len - len;
2997         for( comp.bv_len=0;
2998                 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
2999                 comp.bv_len++ )
3000         {
3001                 /* empty */
3002         }
3003
3004         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
3005                 rc = numericoidValidate( NULL, &comp );
3006         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
3007                 rc = integerValidate( NULL, &comp );
3008         } else {
3009                 rc = LDAP_INVALID_SYNTAX;
3010         }
3011         
3012
3013         if( rc == LDAP_SUCCESS ) {
3014                 ber_dupbv_x( normalized, &comp, ctx );
3015         }
3016
3017         return rc;
3018 }
3019
3020
3021 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
3022 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
3023
3024 static slap_syntax_defs_rec syntax_defs[] = {
3025         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
3026                 X_BINARY X_NOT_H_R ")",
3027                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL},
3028         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
3029                 0, NULL, NULL},
3030         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
3031                 0, NULL, NULL},
3032         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
3033                 X_NOT_H_R ")",
3034                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3035         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
3036                 X_NOT_H_R ")",
3037                 SLAP_SYNTAX_BER, berValidate, NULL},
3038         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
3039                 0, bitStringValidate, NULL },
3040         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
3041                 0, booleanValidate, NULL},
3042         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
3043                 X_BINARY X_NOT_H_R ")",
3044                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, certificateValidate, NULL},
3045         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
3046                 X_BINARY X_NOT_H_R ")",
3047                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3048         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
3049                 X_BINARY X_NOT_H_R ")",
3050                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3051         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
3052                 0, countryStringValidate, NULL},
3053         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
3054                 0, dnValidate, dnPretty},
3055         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
3056                 0, NULL, NULL},
3057         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
3058                 0, deliveryMethodValidate, NULL},
3059         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
3060                 0, UTF8StringValidate, NULL},
3061         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
3062                 0, NULL, NULL},
3063         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
3064                 0, NULL, NULL},
3065         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
3066                 0, NULL, NULL},
3067         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
3068                 0, NULL, NULL},
3069         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
3070                 0, NULL, NULL},
3071         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
3072                 0, printablesStringValidate, NULL},
3073         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
3074                 SLAP_SYNTAX_BLOB, NULL, NULL},
3075         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
3076                 0, generalizedTimeValidate, NULL},
3077         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
3078                 0, NULL, NULL},
3079         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
3080                 0, IA5StringValidate, NULL},
3081         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
3082                 0, integerValidate, NULL},
3083         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
3084                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3085         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
3086                 0, NULL, NULL},
3087         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
3088                 0, NULL, NULL},
3089         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
3090                 0, NULL, NULL},
3091         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
3092                 0, NULL, NULL},
3093         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
3094                 0, NULL, NULL},
3095         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
3096                 0, nameUIDValidate, nameUIDPretty },
3097         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
3098                 0, NULL, NULL},
3099         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
3100                 0, numericStringValidate, NULL},
3101         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
3102                 0, NULL, NULL},
3103         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
3104                 0, numericoidValidate, NULL},
3105         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
3106                 0, IA5StringValidate, NULL},
3107         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
3108                 0, blobValidate, NULL},
3109         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
3110                 0, UTF8StringValidate, NULL},
3111         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
3112                 0, NULL, NULL},
3113         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
3114                 0, NULL, NULL},
3115         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
3116                 0, printableStringValidate, NULL},
3117         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
3118 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
3119                 0, subtreeSpecificationValidate, NULL},
3120         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
3121                 X_BINARY X_NOT_H_R ")",
3122                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
3123         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
3124                 0, printableStringValidate, NULL},
3125         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
3126                 0, NULL, NULL},
3127         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
3128                 0, printablesStringValidate, NULL},
3129 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3130         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
3131                 0, utcTimeValidate, NULL},
3132 #endif
3133         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
3134                 0, NULL, NULL},
3135         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
3136                 0, NULL, NULL},
3137         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
3138                 0, NULL, NULL},
3139         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
3140                 0, NULL, NULL},
3141         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
3142                 0, NULL, NULL},
3143
3144         /* RFC 2307 NIS Syntaxes */
3145         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
3146                 0, nisNetgroupTripleValidate, NULL},
3147         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
3148                 0, bootParameterValidate, NULL},
3149
3150         /* From PKIX *//* This OID is not published yet. */
3151         {"( 1.2.826.0.1.3344810.7.1 DESC 'Certificate Serial Number and Issuer' )",
3152                 SLAP_SYNTAX_HIDE,
3153                 serialNumberAndIssuerValidate,
3154                 serialNumberAndIssuerPretty},
3155
3156 #ifdef SLAPD_ACI_ENABLED
3157         /* OpenLDAP Experimental Syntaxes */
3158         {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
3159                 SLAP_SYNTAX_HIDE,
3160                 UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
3161                 NULL},
3162 #endif
3163
3164 #ifdef SLAPD_AUTHPASSWD
3165         /* needs updating */
3166         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
3167                 SLAP_SYNTAX_HIDE, NULL, NULL},
3168 #endif
3169
3170         {"( 1.3.6.1.4.1.4203.666.2.6 DESC 'UUID' )",
3171                 SLAP_SYNTAX_HIDE, UUIDValidate, NULL},
3172
3173         /* OpenLDAP Void Syntax */
3174         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
3175                 SLAP_SYNTAX_HIDE, inValidate, NULL},
3176         {NULL, 0, NULL, NULL}
3177 };
3178
3179 char *certificateExactMatchSyntaxes[] = {
3180         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
3181         NULL
3182 };
3183 char *directoryStringSyntaxes[] = {
3184         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
3185         NULL
3186 };
3187 char *integerFirstComponentMatchSyntaxes[] = {
3188         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
3189         "1.3.6.1.4.1.1466.115.121.1.17" /* ditStructureRuleDescription */,
3190         NULL
3191 };
3192 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
3193         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
3194         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
3195         "1.3.6.1.4.1.1466.115.121.1.16" /* ditContentRuleDescription */,
3196         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
3197         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
3198         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
3199         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
3200         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
3201         NULL
3202 };
3203
3204 /*
3205  * Other matching rules in X.520 that we do not use (yet):
3206  *
3207  * 2.5.13.25    uTCTimeMatch
3208  * 2.5.13.26    uTCTimeOrderingMatch
3209  * 2.5.13.31*   directoryStringFirstComponentMatch
3210  * 2.5.13.32*   wordMatch
3211  * 2.5.13.33*   keywordMatch
3212  * 2.5.13.36    certificatePairExactMatch
3213  * 2.5.13.37    certificatePairMatch
3214  * 2.5.13.38    certificateListExactMatch
3215  * 2.5.13.39    certificateListMatch
3216  * 2.5.13.40    algorithmIdentifierMatch
3217  * 2.5.13.41*   storedPrefixMatch
3218  * 2.5.13.42    attributeCertificateMatch
3219  * 2.5.13.43    readerAndKeyIDMatch
3220  * 2.5.13.44    attributeIntegrityMatch
3221  *
3222  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
3223  */
3224 static slap_mrule_defs_rec mrule_defs[] = {
3225         /*
3226          * EQUALITY matching rules must be listed after associated APPROX
3227          * matching rules.  So, we list all APPROX matching rules first.
3228          */
3229         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
3230                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3231                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3232                 NULL, NULL, directoryStringApproxMatch,
3233                 directoryStringApproxIndexer, directoryStringApproxFilter,
3234                 NULL},
3235
3236         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
3237                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3238                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3239                 NULL, NULL, IA5StringApproxMatch,
3240                 IA5StringApproxIndexer, IA5StringApproxFilter,
3241                 NULL},
3242
3243         /*
3244          * Other matching rules
3245          */
3246         
3247         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
3248                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3249                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3250                 NULL, NULL, octetStringMatch,
3251                 octetStringIndexer, octetStringFilter,
3252                 NULL },
3253
3254         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
3255                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3256                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3257                 NULL, dnNormalize, dnMatch,
3258                 octetStringIndexer, octetStringFilter,
3259                 NULL },
3260
3261         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
3262                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3263                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3264                 NULL, UTF8StringNormalize, octetStringMatch,
3265                 octetStringIndexer, octetStringFilter,
3266                 directoryStringApproxMatchOID },
3267
3268         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
3269                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3270                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3271                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3272                 NULL, NULL,
3273                 "caseIgnoreMatch" },
3274
3275         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
3276                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3277                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3278                 NULL, UTF8StringNormalize, octetStringSubstringsMatch,
3279                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3280                 "caseIgnoreMatch" },
3281
3282         {"( 2.5.13.5 NAME 'caseExactMatch' "
3283                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3284                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3285                 NULL, UTF8StringNormalize, octetStringMatch,
3286                 octetStringIndexer, octetStringFilter,
3287                 directoryStringApproxMatchOID },
3288
3289         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
3290                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3291                 SLAP_MR_ORDERING, directoryStringSyntaxes,
3292                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3293                 NULL, NULL,
3294                 "caseExactMatch" },
3295
3296         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
3297                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3298                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3299                 NULL, UTF8StringNormalize, octetStringSubstringsMatch,
3300                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3301                 "caseExactMatch" },
3302
3303         {"( 2.5.13.8 NAME 'numericStringMatch' "
3304                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3305                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3306                 NULL, numericStringNormalize, octetStringMatch,
3307                 octetStringIndexer, octetStringFilter,
3308                 NULL },
3309
3310         {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
3311                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3312                 SLAP_MR_ORDERING, NULL,
3313                 NULL, numericStringNormalize, octetStringOrderingMatch,
3314                 NULL, NULL,
3315                 "numericStringMatch" },
3316
3317         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
3318                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3319                 SLAP_MR_SUBSTR, NULL,
3320                 NULL, numericStringNormalize, octetStringSubstringsMatch,
3321                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3322                 "numericStringMatch" },
3323
3324         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
3325                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
3326                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3327                 NULL, NULL, NULL, NULL, NULL, NULL },
3328
3329         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
3330                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3331                 SLAP_MR_SUBSTR, NULL,
3332                 NULL, NULL, NULL, NULL, NULL,
3333                 "caseIgnoreListMatch" },
3334
3335         {"( 2.5.13.13 NAME 'booleanMatch' "
3336                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
3337                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3338                 NULL, NULL, booleanMatch,
3339                 octetStringIndexer, octetStringFilter,
3340                 NULL },
3341
3342         {"( 2.5.13.14 NAME 'integerMatch' "
3343                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3344                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3345                 NULL, NULL, integerMatch,
3346                 octetStringIndexer, octetStringFilter,
3347                 NULL },
3348
3349         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
3350                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3351                 SLAP_MR_ORDERING, NULL,
3352                 NULL, NULL, integerMatch,
3353                 NULL, NULL,
3354                 "integerMatch" },
3355
3356         {"( 2.5.13.16 NAME 'bitStringMatch' "
3357                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
3358                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3359                 NULL, NULL, octetStringMatch,
3360                 octetStringIndexer, octetStringFilter,
3361                 NULL },
3362
3363         {"( 2.5.13.17 NAME 'octetStringMatch' "
3364                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3365                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3366                 NULL, NULL, octetStringMatch,
3367                 octetStringIndexer, octetStringFilter,
3368                 NULL },
3369
3370         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
3371                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3372                 SLAP_MR_ORDERING, NULL,
3373                 NULL, NULL, octetStringOrderingMatch,
3374                 NULL, NULL,
3375                 "octetStringMatch" },
3376
3377         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
3378                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3379                 SLAP_MR_SUBSTR, NULL,
3380                 NULL, NULL, octetStringSubstringsMatch,
3381                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3382                 "octetStringMatch" },
3383
3384         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
3385                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
3386                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3387                 NULL,
3388                 telephoneNumberNormalize, octetStringMatch,
3389                 octetStringIndexer, octetStringFilter,
3390                 NULL },
3391
3392         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
3393                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3394                 SLAP_MR_SUBSTR, NULL,
3395                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
3396                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3397                 "telephoneNumberMatch" },
3398
3399         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
3400                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
3401                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3402                 NULL, NULL, NULL, NULL, NULL, NULL },
3403
3404         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
3405                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
3406                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3407                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
3408                 NULL, NULL,
3409                 NULL },
3410
3411         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
3412                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
3413                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3414                 NULL, NULL, NULL, NULL, NULL, NULL },
3415
3416         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
3417                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3418                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3419                 NULL, generalizedTimeNormalize, octetStringMatch,
3420                 NULL, NULL,
3421                 NULL },
3422
3423         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
3424                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3425                 SLAP_MR_ORDERING, NULL,
3426                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
3427                 NULL, NULL,
3428                 "generalizedTimeMatch" },
3429
3430         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
3431                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3432                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3433                         integerFirstComponentMatchSyntaxes,
3434                 NULL, firstComponentNormalize, integerMatch,
3435                 octetStringIndexer, octetStringFilter,
3436                 NULL },
3437
3438         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
3439                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3440                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3441                         objectIdentifierFirstComponentMatchSyntaxes,
3442                 NULL, firstComponentNormalize, octetStringMatch,
3443                 octetStringIndexer, octetStringFilter,
3444                 NULL },
3445
3446         {"( 2.5.13.34 NAME 'certificateExactMatch' "
3447                 "SYNTAX 1.2.826.0.1.3344810.7.1 )",
3448                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
3449 #ifdef HAVE_TLS
3450                 NULL, certificateExactNormalize, octetStringMatch,
3451                 octetStringIndexer, octetStringFilter,
3452 #else
3453                 NULL, NULL, NULL, NULL, NULL,
3454 #endif
3455                 NULL },
3456
3457         {"( 2.5.13.35 NAME 'certificateMatch' "
3458                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )",
3459                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3460 #ifdef HAVE_TLS
3461                 NULL, NULL, octetStringMatch,
3462                 octetStringIndexer, octetStringFilter,
3463 #else
3464                 NULL, NULL, NULL, NULL, NULL,
3465 #endif
3466                 NULL },
3467
3468         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
3469                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3470                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3471                 NULL, IA5StringNormalize, octetStringMatch,
3472                 octetStringIndexer, octetStringFilter,
3473                 IA5StringApproxMatchOID },
3474
3475         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
3476                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3477                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3478                 NULL, IA5StringNormalize, octetStringMatch,
3479                 octetStringIndexer, octetStringFilter,
3480                 IA5StringApproxMatchOID },
3481
3482         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
3483                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3484                 SLAP_MR_SUBSTR, NULL,
3485                 NULL, IA5StringNormalize, octetStringSubstringsMatch,
3486                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3487                 "caseIgnoreIA5Match" },
3488
3489         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
3490                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3491                 SLAP_MR_SUBSTR, NULL,
3492                 NULL, IA5StringNormalize, octetStringSubstringsMatch,
3493                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3494                 "caseExactIA5Match" },
3495
3496 #ifdef SLAPD_AUTHPASSWD
3497         /* needs updating */
3498         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
3499                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3500                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3501                 NULL, NULL, authPasswordMatch,
3502                 NULL, NULL,
3503                 NULL},
3504 #endif
3505
3506 #ifdef SLAPD_ACI_ENABLED
3507         {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
3508                 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
3509                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3510                 NULL, NULL, OpenLDAPaciMatch,
3511                 NULL, NULL,
3512                 NULL},
3513 #endif
3514
3515         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
3516                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3517                 SLAP_MR_EXT, NULL,
3518                 NULL, NULL, integerBitAndMatch,
3519                 NULL, NULL,
3520                 "integerMatch" },
3521
3522         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
3523                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3524                 SLAP_MR_EXT, NULL,
3525                 NULL, NULL, integerBitOrMatch,
3526                 NULL, NULL,
3527                 "integerMatch" },
3528
3529         {"( 1.3.6.1.4.1.4203.666.4.6 NAME 'UUIDMatch' "
3530                 "SYNTAX 1.3.6.1.4.1.4203.666.2.6 )",
3531                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3532                 NULL, UUIDNormalize, octetStringMatch,
3533                 octetStringIndexer, octetStringFilter,
3534                 NULL},
3535
3536         {"( 1.3.6.1.4.1.4203.666.4.7 NAME 'UUIDOrderingMatch' "
3537                 "SYNTAX 1.3.6.1.4.1.4203.666.2.6 )",
3538                 SLAP_MR_HIDE | SLAP_MR_ORDERING, NULL,
3539                 NULL, UUIDNormalize, octetStringOrderingMatch,
3540                 octetStringIndexer, octetStringFilter,
3541                 "UUIDMatch"},
3542
3543         {NULL, SLAP_MR_NONE, NULL,
3544                 NULL, NULL, NULL, NULL, NULL,
3545                 NULL }
3546 };
3547
3548 int
3549 slap_schema_init( void )
3550 {
3551         int             res;
3552         int             i;
3553
3554         /* we should only be called once (from main) */
3555         assert( schema_init_done == 0 );
3556
3557         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
3558                 res = register_syntax( &syntax_defs[i] );
3559
3560                 if ( res ) {
3561                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
3562                                  syntax_defs[i].sd_desc );
3563                         return LDAP_OTHER;
3564                 }
3565         }
3566
3567         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
3568                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
3569                         mrule_defs[i].mrd_compat_syntaxes == NULL )
3570                 {
3571                         fprintf( stderr,
3572                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
3573                                  mrule_defs[i].mrd_desc );
3574                         continue;
3575                 }
3576
3577                 res = register_matching_rule( &mrule_defs[i] );
3578
3579                 if ( res ) {
3580                         fprintf( stderr,
3581                                 "slap_schema_init: Error registering matching rule %s\n",
3582                                  mrule_defs[i].mrd_desc );
3583                         return LDAP_OTHER;
3584                 }
3585         }
3586
3587         res = slap_schema_load();
3588         schema_init_done = 1;
3589         return res;
3590 }
3591
3592 void
3593 schema_destroy( void )
3594 {
3595         oidm_destroy();
3596         oc_destroy();
3597         at_destroy();
3598         mr_destroy();
3599         mru_destroy();
3600         syn_destroy();
3601 }