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