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