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