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