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