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