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