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