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