]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
a51c4e63f444aae4a02d1614cee4012f48f93c8a
[openldap] / servers / slapd / schema_init.c
1 /* schema_init.c - init builtin schema */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 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
12 #include <ac/ctype.h>
13 #include <ac/string.h>
14 #include <ac/socket.h>
15
16 #include "slap.h"
17 #include "ldap_pvt.h"
18 #include "lutil_md5.h"
19
20 /* recycled validatation routines */
21 #define berValidate                                             blobValidate
22
23 /* unimplemented validators */
24 #define bitStringValidate                               NULL
25 #define booleanValidate                                 NULL
26
27 /* recycled normalization routines */
28 #define faxNumberNormalize                              numericStringNormalize
29 #define phoneNumberNormalize                    numericStringNormalize
30 #define telexNumberNormalize                    numericStringNormalize
31 #define integerNormalize                                numericStringNormalize
32
33 /* unimplemented normalizers */
34 #define bitStringNormalize                              NULL
35 #define booleanNormalize                                NULL
36
37 /* unimplemented pretters */
38 #define booleanPretty                                   NULL
39 #define dnPretty                                                NULL
40 #define integerPretty                                   NULL
41
42 /* recycled matching routines */
43 #define caseIgnoreMatch                                 caseIgnoreIA5Match
44 #define caseIgnoreOrderingMatch                 caseIgnoreMatch
45 #define caseIgnoreSubstringsMatch               caseIgnoreIA5SubstringsMatch
46
47 #define caseExactMatch                                  caseExactIA5Match
48 #define caseExactOrderingMatch                  caseExactMatch
49 #define caseExactSubstringsMatch                caseExactIA5SubstringsMatch
50
51 #define numericStringMatch                              caseIgnoreMatch
52 #define objectIdentifierMatch                   numericStringMatch
53 #define integerMatch                                    numericStringMatch
54 #define telephoneNumberMatch                    numericStringMatch
55 #define telephoneNumberSubstringsMatch  caseIgnoreIA5SubstringsMatch
56 #define generalizedTimeMatch                    numericStringMatch
57 #define generalizedTimeOrderingMatch    numericStringMatch
58
59 /* unimplemented matching routines */
60 #define caseIgnoreListMatch                             NULL
61 #define caseIgnoreListSubstringsMatch   NULL
62 #define bitStringMatch                                  NULL
63 #define presentationAddressMatch                NULL
64 #define uniqueMemberMatch                               NULL
65 #define protocolInformationMatch                NULL
66 #define integerFirstComponentMatch              NULL
67
68 #define OpenLDAPaciMatch                                NULL
69 #define authPasswordMatch                               NULL
70
71 /* unimplied indexer/filter routines */
72 #define caseIgnoreIA5SubstringsIndexer  NULL
73 #define caseIgnoreIA5SubstringsFilter   NULL
74
75 /* recycled indexing/filtering routines */
76 #define caseIgnoreIndexer                               caseIgnoreIA5Indexer
77 #define caseIgnoreFilter                                caseIgnoreIA5Filter
78 #define caseExactIndexer                                caseExactIA5Indexer
79 #define caseExactFilter                                 caseExactIA5Filter
80 #define dnIndexer                                               caseIgnoreIndexer
81 #define dnFilter                                                caseIgnoreFilter
82
83 #define caseIgnoreSubstringsIndexer             caseIgnoreIA5SubstringsIndexer
84 #define caseIgnoreSubstringsFilter              caseIgnoreIA5SubstringsFilter
85 #define caseExactSubstringsIndexer              caseExactIA5SubstringsIndexer
86 #define caseExactSubstringsFilter               caseExactIA5SubstringsFilter
87 #define caseExactIA5SubstringsFilter    caseIgnoreIA5SubstringsFilter
88 #define caseExactIA5SubstringsIndexer   caseIgnoreIA5SubstringsIndexer
89
90
91 static int
92 octetStringMatch(
93         int *matchp,
94         unsigned flags,
95         Syntax *syntax,
96         MatchingRule *mr,
97         struct berval *value,
98         void *assertedValue )
99 {
100         int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
101
102         if( match == 0 ) {
103                 match = memcmp( value->bv_val,
104                         ((struct berval *) assertedValue)->bv_val,
105                         value->bv_len );
106         }
107
108         *matchp = match;
109         return LDAP_SUCCESS;
110 }
111
112 /* Index generation function */
113 int octetStringIndexer(
114         unsigned flags,
115         Syntax *syntax,
116         MatchingRule *mr,
117         struct berval *prefix,
118         struct berval **values,
119         struct berval ***keysp )
120 {
121         int i;
122         size_t slen, mlen;
123         struct berval **keys;
124         lutil_MD5_CTX   MD5context;
125         unsigned char   MD5digest[16];
126         struct berval digest;
127         digest.bv_val = MD5digest;
128         digest.bv_len = sizeof(MD5digest);
129
130         for( i=0; values[i] != NULL; i++ ) {
131                 /* just count them */
132         }
133
134         assert( i > 0 );
135
136         keys = ch_malloc( sizeof( struct berval * ) * (i+1) );
137
138         slen = strlen( syntax->ssyn_oid );
139         mlen = strlen( mr->smr_oid );
140
141         for( i=0; values[i] != NULL; i++ ) {
142                 lutil_MD5Init( &MD5context );
143                 if( prefix != NULL && prefix->bv_len > 0 ) {
144                         lutil_MD5Update( &MD5context,
145                                 prefix->bv_val, prefix->bv_len );
146                 }
147                 lutil_MD5Update( &MD5context,
148                         syntax->ssyn_oid, slen );
149                 lutil_MD5Update( &MD5context,
150                         mr->smr_oid, mlen );
151                 lutil_MD5Update( &MD5context,
152                         values[i]->bv_val, values[i]->bv_len );
153                 lutil_MD5Final( MD5digest, &MD5context );
154
155                 keys[i] = ber_bvdup( &digest );
156         }
157
158         keys[i] = NULL;
159
160         *keysp = keys;
161
162         return LDAP_SUCCESS;
163 }
164
165 /* Index generation function */
166 int octetStringFilter(
167         unsigned flags,
168         Syntax *syntax,
169         MatchingRule *mr,
170         struct berval *prefix,
171         void * assertValue,
172         struct berval ***keysp )
173 {
174         size_t slen, mlen;
175         struct berval **keys;
176         lutil_MD5_CTX   MD5context;
177         unsigned char   MD5digest[LUTIL_MD5_BYTES];
178         struct berval *value = (struct berval *) assertValue;
179         struct berval digest;
180         digest.bv_val = MD5digest;
181         digest.bv_len = sizeof(MD5digest);
182
183         slen = strlen( syntax->ssyn_oid );
184         mlen = strlen( mr->smr_oid );
185
186         keys = ch_malloc( sizeof( struct berval * ) * 2 );
187
188         lutil_MD5Init( &MD5context );
189         if( prefix != NULL && prefix->bv_len > 0 ) {
190                 lutil_MD5Update( &MD5context,
191                         prefix->bv_val, prefix->bv_len );
192         }
193         lutil_MD5Update( &MD5context,
194                 syntax->ssyn_oid, slen );
195         lutil_MD5Update( &MD5context,
196                 mr->smr_oid, mlen );
197         lutil_MD5Update( &MD5context,
198                 value->bv_val, value->bv_len );
199         lutil_MD5Final( MD5digest, &MD5context );
200
201         keys[0] = ber_bvdup( &digest );
202         keys[1] = NULL;
203
204         *keysp = keys;
205
206         return LDAP_SUCCESS;
207 }
208
209 static int
210 dnValidate(
211         Syntax *syntax,
212         struct berval *in )
213 {
214         int rc;
215         char *dn;
216
217         if( in->bv_len == 0 ) return LDAP_SUCCESS;
218
219         dn = ch_strdup( in->bv_val );
220
221         rc = dn_validate( dn ) == NULL
222                 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
223
224         ch_free( dn );
225         return rc;
226 }
227
228 static int
229 dnNormalize(
230         Syntax *syntax,
231         struct berval *val,
232         struct berval **normalized )
233 {
234         struct berval *out = ber_bvdup( val );
235
236         if( out->bv_len != 0 ) {
237                 char *dn;
238 #ifdef USE_DN_NORMALIZE
239                 dn = dn_normalize( out->bv_val );
240 #else
241                 dn = dn_validate( out->bv_val );
242 #endif
243
244                 if( dn == NULL ) {
245                         ber_bvfree( out );
246                         return LDAP_INVALID_SYNTAX;
247                 }
248
249                 out->bv_val = dn;
250                 out->bv_len = strlen( dn );
251         }
252
253         *normalized = out;
254         return LDAP_SUCCESS;
255 }
256
257 static int
258 dnMatch(
259         int *matchp,
260         unsigned flags,
261         Syntax *syntax,
262         MatchingRule *mr,
263         struct berval *value,
264         void *assertedValue )
265 {
266         int match;
267         struct berval *asserted = (struct berval *) assertedValue;
268         
269         match = value->bv_len - asserted->bv_len;
270
271         if( match == 0 ) {
272 #ifdef USE_DN_NORMALIZE
273                 match = strcmp( value->bv_val, asserted->bv_val );
274 #else
275                 match = strcasecmp( value->bv_val, asserted->bv_val );
276 #endif
277         }
278
279         Debug( LDAP_DEBUG_ARGS, "dnMatch %d\n\t\"%s\"\n\t\"%s\"\n",
280             match, value->bv_val, asserted->bv_val );
281
282         *matchp = match;
283         return LDAP_SUCCESS;
284 }
285
286 static int
287 inValidate(
288         Syntax *syntax,
289         struct berval *in )
290 {
291         /* any value allowed */
292         return LDAP_OTHER;
293 }
294
295 static int
296 blobValidate(
297         Syntax *syntax,
298         struct berval *in )
299 {
300         /* any value allowed */
301         return LDAP_SUCCESS;
302 }
303
304 static int
305 UTF8StringValidate(
306         Syntax *syntax,
307         struct berval *in )
308 {
309         ber_len_t count;
310         int len;
311         unsigned char *u = in->bv_val;
312
313         if( !in->bv_len ) return LDAP_INVALID_SYNTAX;
314
315         for( count = in->bv_len; count > 0; count-=len, u+=len ) {
316                 /* get the length indicated by the first byte */
317                 len = LDAP_UTF8_CHARLEN( u );
318
319                 /* should not be zero */
320                 if( len == 0 ) return LDAP_INVALID_SYNTAX;
321
322                 /* make sure len corresponds with the offset
323                         to the next character */
324                 if( LDAP_UTF8_OFFSET( u ) != len ) return LDAP_INVALID_SYNTAX;
325         }
326
327         if( count != 0 ) return LDAP_INVALID_SYNTAX;
328
329         return LDAP_SUCCESS;
330 }
331
332 static int
333 UTF8StringNormalize(
334         Syntax *syntax,
335         struct berval *val,
336         struct berval **normalized )
337 {
338         struct berval *newval;
339         char *p, *q, *s;
340
341         newval = ch_malloc( sizeof( struct berval ) );
342
343         p = val->bv_val;
344
345         /* Ignore initial whitespace */
346         while ( ldap_utf8_isspace( p ) ) {
347                 LDAP_UTF8_INCR( p );
348         }
349
350         if( *p == '\0' ) {
351                 ch_free( newval );
352                 return LDAP_INVALID_SYNTAX;
353         }
354
355         newval->bv_val = ch_strdup( p );
356         p = q = newval->bv_val;
357         s = NULL;
358
359         while ( *p ) {
360                 int len;
361
362                 if ( ldap_utf8_isspace( p ) ) {
363                         len = LDAP_UTF8_COPY(q,p);
364                         s=q;
365                         p+=len;
366                         q+=len;
367
368                         /* Ignore the extra whitespace */
369                         while ( ldap_utf8_isspace( p ) ) {
370                                 LDAP_UTF8_INCR( p );
371                         }
372                 } else {
373                         len = LDAP_UTF8_COPY(q,p);
374                         s=NULL;
375                         p+=len;
376                         q+=len;
377                 }
378         }
379
380         assert( *newval->bv_val );
381         assert( newval->bv_val < p );
382         assert( p >= q );
383
384         /* cannot start with a space */
385         assert( !ldap_utf8_isspace(newval->bv_val) );
386
387         /*
388          * If the string ended in space, backup the pointer one
389          * position.  One is enough because the above loop collapsed
390          * all whitespace to a single space.
391          */
392
393         if ( s != NULL ) {
394                 q = s;
395         }
396
397         /* cannot end with a space */
398         assert( !ldap_utf8_isspace( LDAP_UTF8_PREV(q) ) );
399
400         /* null terminate */
401         *q = '\0';
402
403         newval->bv_len = q - newval->bv_val;
404         *normalized = newval;
405
406         return LDAP_SUCCESS;
407 }
408
409 static int
410 oidValidate(
411         Syntax *syntax,
412         struct berval *val )
413 {
414         ber_len_t i;
415
416         if( val->bv_len == 0 ) return 0;
417
418         if( OID_LEADCHAR(val->bv_val[0]) ) {
419                 int dot = 0;
420                 for(i=1; i < val->bv_len; i++) {
421                         if( OID_SEPARATOR( val->bv_val[i] ) ) {
422                                 if( dot++ ) return 1;
423                         } else if ( OID_CHAR( val->bv_val[i] ) ) {
424                                 dot = 0;
425                         } else {
426                                 return LDAP_INVALID_SYNTAX;
427                         }
428                 }
429
430                 return !dot ? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
431
432         } else if( DESC_LEADCHAR(val->bv_val[0]) ) {
433                 for(i=1; i < val->bv_len; i++) {
434                         if( !DESC_CHAR(val->bv_val[i] ) ) {
435                                 return LDAP_INVALID_SYNTAX;
436                         }
437                 }
438
439                 return LDAP_SUCCESS;
440         }
441         
442         return LDAP_INVALID_SYNTAX;
443 }
444
445 static int
446 integerValidate(
447         Syntax *syntax,
448         struct berval *val )
449 {
450         ber_len_t i;
451
452         if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
453
454         for(i=0; i < val->bv_len; i++) {
455                 if( !ASCII_DIGIT(val->bv_val[i]) ) return LDAP_INVALID_SYNTAX;
456         }
457
458         return LDAP_SUCCESS;
459 }
460
461 static int
462 printableStringValidate(
463         Syntax *syntax,
464         struct berval *val )
465 {
466         ber_len_t i;
467
468         if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
469
470         for(i=0; i < val->bv_len; i++) {
471                 if( !isprint(val->bv_val[i]) ) return LDAP_INVALID_SYNTAX;
472         }
473
474         return LDAP_SUCCESS;
475 }
476
477 static int
478 IA5StringValidate(
479         Syntax *syntax,
480         struct berval *val )
481 {
482         ber_len_t i;
483
484         if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
485
486         for(i=0; i < val->bv_len; i++) {
487                 if( !isascii(val->bv_val[i]) ) return LDAP_INVALID_SYNTAX;
488         }
489
490         return LDAP_SUCCESS;
491 }
492
493 static int
494 IA5StringConvert(
495         Syntax *syntax,
496         struct berval *in,
497         struct berval **out )
498 {
499         ldap_unicode_t *u;
500         ber_len_t i, len = in->bv_len;
501         struct berval *bv = ch_malloc( sizeof(struct berval) );
502
503         bv->bv_len = len * sizeof( ldap_unicode_t );
504         bv->bv_val = (char *) u = ch_malloc( bv->bv_len + sizeof(ldap_unicode_t) );
505
506         for(i=0; i < len; i++ ) {
507                 /*
508                  * IA5StringValidate should have been called to ensure
509                  * input is limited to IA5.
510                  */
511                 u[i] = in->bv_val[i];
512         }
513         u[i] = 0;
514
515         *out = bv;
516         return LDAP_SUCCESS;
517 }
518
519 static int
520 IA5StringNormalize(
521         Syntax *syntax,
522         struct berval *val,
523         struct berval **normalized )
524 {
525         struct berval *newval;
526         char *p, *q;
527
528         newval = ch_malloc( sizeof( struct berval ) );
529
530         p = val->bv_val;
531
532         /* Ignore initial whitespace */
533         while ( ASCII_SPACE( *p ) ) {
534                 p++;
535         }
536
537         if( *p != '\0' ) {
538                 ch_free( newval );
539                 return LDAP_INVALID_SYNTAX;
540         }
541
542         newval->bv_val = ch_strdup( p );
543         p = q = newval->bv_val;
544
545         while ( *p ) {
546                 if ( ASCII_SPACE( *p ) ) {
547                         *q++ = *p++;
548
549                         /* Ignore the extra whitespace */
550                         while ( ASCII_SPACE( *p ) ) {
551                                 p++;
552                         }
553                 } else {
554                         *q++ = *p++;
555                 }
556         }
557
558         assert( *newval->bv_val );
559         assert( newval->bv_val < p );
560         assert( p <= q );
561
562         /* cannot start with a space */
563         assert( !ASCII_SPACE(*newval->bv_val) );
564
565         /*
566          * If the string ended in space, backup the pointer one
567          * position.  One is enough because the above loop collapsed
568          * all whitespace to a single space.
569          */
570
571         if ( ASCII_SPACE( q[-1] ) ) {
572                 --q;
573         }
574
575         /* cannot end with a space */
576         assert( !ASCII_SPACE( q[-1] ) );
577
578         /* null terminate */
579         *q = '\0';
580
581         newval->bv_len = q - newval->bv_val;
582         *normalized = newval;
583
584         return LDAP_SUCCESS;
585 }
586
587 static int
588 caseExactIA5Match(
589         int *matchp,
590         unsigned flags,
591         Syntax *syntax,
592         MatchingRule *mr,
593         struct berval *value,
594         void *assertedValue )
595 {
596         int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
597
598         if( match == 0 ) {
599                 match = strncmp( value->bv_val,
600                         ((struct berval *) assertedValue)->bv_val,
601                         value->bv_len );
602         }
603
604         *matchp = match;
605         return LDAP_SUCCESS;
606 }
607
608 static int
609 caseExactIA5SubstringsMatch(
610         int *matchp,
611         unsigned flags,
612         Syntax *syntax,
613         MatchingRule *mr,
614         struct berval *value,
615         void *assertedValue )
616 {
617         int match = 0;
618         SubstringsAssertion *sub = assertedValue;
619         struct berval left = *value;
620         int i;
621         ber_len_t inlen=0;
622
623         /* Add up asserted input length */
624         if( sub->sa_initial ) {
625                 inlen += sub->sa_initial->bv_len;
626         }
627         if( sub->sa_any ) {
628                 for(i=0; sub->sa_any[i] != NULL; i++) {
629                         inlen += sub->sa_any[i]->bv_len;
630                 }
631         }
632         if( sub->sa_final ) {
633                 inlen += sub->sa_final->bv_len;
634         }
635
636         if( sub->sa_initial ) {
637                 if( inlen > left.bv_len ) {
638                         match = 1;
639                         goto done;
640                 }
641
642                 match = strncmp( sub->sa_initial->bv_val, left.bv_val,
643                         sub->sa_initial->bv_len );
644
645                 if( match != 0 ) {
646                         goto done;
647                 }
648
649                 left.bv_val += sub->sa_initial->bv_len;
650                 left.bv_len -= sub->sa_initial->bv_len;
651                 inlen -= sub->sa_initial->bv_len;
652         }
653
654         if( sub->sa_final ) {
655                 if( inlen > left.bv_len ) {
656                         match = 1;
657                         goto done;
658                 }
659
660                 match = strncmp( sub->sa_final->bv_val,
661                         &left.bv_val[left.bv_len - sub->sa_final->bv_len],
662                         sub->sa_final->bv_len );
663
664                 if( match != 0 ) {
665                         goto done;
666                 }
667
668                 left.bv_len -= sub->sa_final->bv_len;
669                 inlen -= sub->sa_final->bv_len;
670         }
671
672         if( sub->sa_any ) {
673                 for(i=0; sub->sa_any[i]; i++) {
674                         ber_len_t idx;
675                         char *p;
676
677 retry:
678                         if( inlen > left.bv_len ) {
679                                 /* not enough length */
680                                 match = 1;
681                                 goto done;
682                         }
683
684                         if( sub->sa_any[i]->bv_len == 0 ) {
685                                 continue;
686                         }
687
688                         p = strchr( left.bv_val, *sub->sa_any[i]->bv_val );
689
690                         if( p == NULL ) {
691                                 match = 1;
692                                 goto done;
693                         }
694
695                         idx = p - left.bv_val;
696                         assert( idx < left.bv_len );
697
698                         if( idx >= left.bv_len ) {
699                                 /* this shouldn't happen */
700                                 return LDAP_OTHER;
701                         }
702
703                         left.bv_val = p;
704                         left.bv_len -= idx;
705
706                         if( sub->sa_any[i]->bv_len > left.bv_len ) {
707                                 /* not enough left */
708                                 match = 1;
709                                 goto done;
710                         }
711
712                         match = strncmp( left.bv_val,
713                                 sub->sa_any[i]->bv_val,
714                                 sub->sa_any[i]->bv_len );
715
716                         if( match != 0 ) {
717                                 left.bv_val++;
718                                 left.bv_len--;
719                                 goto retry;
720                         }
721
722                         left.bv_val += sub->sa_any[i]->bv_len;
723                         left.bv_len -= sub->sa_any[i]->bv_len;
724                         inlen -= sub->sa_any[i]->bv_len;
725                 }
726         }
727
728 done:
729         *matchp = match;
730         return LDAP_SUCCESS;
731 }
732
733 /* Index generation function */
734 int caseExactIA5Indexer(
735         unsigned flags,
736         Syntax *syntax,
737         MatchingRule *mr,
738         struct berval *prefix,
739         struct berval **values,
740         struct berval ***keysp )
741 {
742         int i;
743         size_t slen, mlen;
744         struct berval **keys;
745         lutil_MD5_CTX   MD5context;
746         unsigned char   MD5digest[16];
747         struct berval digest;
748         digest.bv_val = MD5digest;
749         digest.bv_len = sizeof(MD5digest);
750
751         for( i=0; values[i] != NULL; i++ ) {
752                 /* just count them */
753         }
754
755         assert( i > 0 );
756
757         keys = ch_malloc( sizeof( struct berval * ) * (i+1) );
758
759         slen = strlen( syntax->ssyn_oid );
760         mlen = strlen( mr->smr_oid );
761
762         for( i=0; values[i] != NULL; i++ ) {
763                 struct berval *value = values[i];
764
765                 lutil_MD5Init( &MD5context );
766                 if( prefix != NULL && prefix->bv_len > 0 ) {
767                         lutil_MD5Update( &MD5context,
768                                 prefix->bv_val, prefix->bv_len );
769                 }
770                 lutil_MD5Update( &MD5context,
771                         syntax->ssyn_oid, slen );
772                 lutil_MD5Update( &MD5context,
773                         mr->smr_oid, mlen );
774                 lutil_MD5Update( &MD5context,
775                         value->bv_val, value->bv_len );
776                 lutil_MD5Final( MD5digest, &MD5context );
777
778                 keys[i] = ber_bvdup( &digest );
779         }
780
781         keys[i] = NULL;
782         *keysp = keys;
783         return LDAP_SUCCESS;
784 }
785
786 /* Index generation function */
787 int caseExactIA5Filter(
788         unsigned flags,
789         Syntax *syntax,
790         MatchingRule *mr,
791         struct berval *prefix,
792         void * assertValue,
793         struct berval ***keysp )
794 {
795         size_t slen, mlen;
796         struct berval **keys;
797         lutil_MD5_CTX   MD5context;
798         unsigned char   MD5digest[LUTIL_MD5_BYTES];
799         struct berval *value;
800         struct berval digest;
801         digest.bv_val = MD5digest;
802         digest.bv_len = sizeof(MD5digest);
803
804         slen = strlen( syntax->ssyn_oid );
805         mlen = strlen( mr->smr_oid );
806
807         value = (struct berval *) assertValue;
808
809         keys = ch_malloc( sizeof( struct berval * ) * 2 );
810
811         lutil_MD5Init( &MD5context );
812         if( prefix != NULL && prefix->bv_len > 0 ) {
813                 lutil_MD5Update( &MD5context,
814                         prefix->bv_val, prefix->bv_len );
815         }
816         lutil_MD5Update( &MD5context,
817                 syntax->ssyn_oid, slen );
818         lutil_MD5Update( &MD5context,
819                 mr->smr_oid, mlen );
820         lutil_MD5Update( &MD5context,
821                 value->bv_val, value->bv_len );
822         lutil_MD5Final( MD5digest, &MD5context );
823
824         keys[0] = ber_bvdup( &digest );
825         keys[1] = NULL;
826
827         *keysp = keys;
828         return LDAP_SUCCESS;
829 }
830
831 static int
832 caseIgnoreIA5Match(
833         int *matchp,
834         unsigned flags,
835         Syntax *syntax,
836         MatchingRule *mr,
837         struct berval *value,
838         void *assertedValue )
839 {
840         int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
841
842         if( match == 0 ) {
843                 match = strncasecmp( value->bv_val,
844                         ((struct berval *) assertedValue)->bv_val,
845                         value->bv_len );
846         }
847
848         *matchp = match;
849         return LDAP_SUCCESS;
850 }
851
852 static char *strcasechr( const char *str, int c )
853 {
854         char *lower = strchr( str, TOLOWER(c) );
855         char *upper = strchr( str, TOUPPER(c) );
856
857         if( lower && upper ) {
858                 return lower < upper ? lower : upper;
859         } else if ( lower ) {
860                 return lower;
861         } else {
862                 return upper;
863         }
864 }
865
866 static int
867 caseIgnoreIA5SubstringsMatch(
868         int *matchp,
869         unsigned flags,
870         Syntax *syntax,
871         MatchingRule *mr,
872         struct berval *value,
873         void *assertedValue )
874 {
875         int match = 0;
876         SubstringsAssertion *sub = assertedValue;
877         struct berval left = *value;
878         int i;
879         ber_len_t inlen=0;
880
881         /* Add up asserted input length */
882         if( sub->sa_initial ) {
883                 inlen += sub->sa_initial->bv_len;
884         }
885         if( sub->sa_any ) {
886                 for(i=0; sub->sa_any[i] != NULL; i++) {
887                         inlen += sub->sa_any[i]->bv_len;
888                 }
889         }
890         if( sub->sa_final ) {
891                 inlen += sub->sa_final->bv_len;
892         }
893
894         if( sub->sa_initial ) {
895                 if( inlen > left.bv_len ) {
896                         match = 1;
897                         goto done;
898                 }
899
900                 match = strncasecmp( sub->sa_initial->bv_val, left.bv_val,
901                         sub->sa_initial->bv_len );
902
903                 if( match != 0 ) {
904                         goto done;
905                 }
906
907                 left.bv_val += sub->sa_initial->bv_len;
908                 left.bv_len -= sub->sa_initial->bv_len;
909                 inlen -= sub->sa_initial->bv_len;
910         }
911
912         if( sub->sa_final ) {
913                 if( inlen > left.bv_len ) {
914                         match = 1;
915                         goto done;
916                 }
917
918                 match = strncasecmp( sub->sa_final->bv_val,
919                         &left.bv_val[left.bv_len - sub->sa_final->bv_len],
920                         sub->sa_final->bv_len );
921
922                 if( match != 0 ) {
923                         goto done;
924                 }
925
926                 left.bv_len -= sub->sa_final->bv_len;
927                 inlen -= sub->sa_final->bv_len;
928         }
929
930         if( sub->sa_any ) {
931                 for(i=0; sub->sa_any[i]; i++) {
932                         ber_len_t idx;
933                         char *p;
934
935 retry:
936                         if( inlen > left.bv_len ) {
937                                 /* not enough length */
938                                 match = 1;
939                                 goto done;
940                         }
941
942                         if( sub->sa_any[i]->bv_len == 0 ) {
943                                 continue;
944                         }
945
946                         p = strcasechr( left.bv_val, *sub->sa_any[i]->bv_val );
947
948                         if( p == NULL ) {
949                                 match = 1;
950                                 goto done;
951                         }
952
953                         idx = p - left.bv_val;
954                         assert( idx < left.bv_len );
955
956                         if( idx >= left.bv_len ) {
957                                 /* this shouldn't happen */
958                                 return LDAP_OTHER;
959                         }
960
961                         left.bv_val = p;
962                         left.bv_len -= idx;
963
964                         if( sub->sa_any[i]->bv_len > left.bv_len ) {
965                                 /* not enough left */
966                                 match = 1;
967                                 goto done;
968                         }
969
970                         match = strncasecmp( left.bv_val,
971                                 sub->sa_any[i]->bv_val,
972                                 sub->sa_any[i]->bv_len );
973
974                         if( match != 0 ) {
975                                 left.bv_val++;
976                                 left.bv_len--;
977
978                                 goto retry;
979                         }
980
981                         left.bv_val += sub->sa_any[i]->bv_len;
982                         left.bv_len -= sub->sa_any[i]->bv_len;
983                         inlen -= sub->sa_any[i]->bv_len;
984                 }
985         }
986
987 done:
988         *matchp = match;
989         return LDAP_SUCCESS;
990 }
991
992 /* Index generation function */
993 int caseIgnoreIA5Indexer(
994         unsigned flags,
995         Syntax *syntax,
996         MatchingRule *mr,
997         struct berval *prefix,
998         struct berval **values,
999         struct berval ***keysp )
1000 {
1001         int i;
1002         size_t slen, mlen;
1003         struct berval **keys;
1004         lutil_MD5_CTX   MD5context;
1005         unsigned char   MD5digest[16];
1006         struct berval digest;
1007         digest.bv_val = MD5digest;
1008         digest.bv_len = sizeof(MD5digest);
1009
1010         for( i=0; values[i] != NULL; i++ ) {
1011                 /* just count them */
1012         }
1013
1014         assert( i > 0 );
1015
1016         keys = ch_malloc( sizeof( struct berval * ) * (i+1) );
1017
1018         slen = strlen( syntax->ssyn_oid );
1019         mlen = strlen( mr->smr_oid );
1020
1021         for( i=0; values[i] != NULL; i++ ) {
1022                 struct berval *value = ber_bvdup( values[i] );
1023                 ldap_pvt_str2upper( value->bv_val );
1024
1025                 lutil_MD5Init( &MD5context );
1026                 if( prefix != NULL && prefix->bv_len > 0 ) {
1027                         lutil_MD5Update( &MD5context,
1028                                 prefix->bv_val, prefix->bv_len );
1029                 }
1030                 lutil_MD5Update( &MD5context,
1031                         syntax->ssyn_oid, slen );
1032                 lutil_MD5Update( &MD5context,
1033                         mr->smr_oid, mlen );
1034                 lutil_MD5Update( &MD5context,
1035                         value->bv_val, value->bv_len );
1036                 lutil_MD5Final( MD5digest, &MD5context );
1037
1038                 ber_bvfree( value );
1039
1040                 keys[i] = ber_bvdup( &digest );
1041         }
1042
1043         keys[i] = NULL;
1044         *keysp = keys;
1045         return LDAP_SUCCESS;
1046 }
1047
1048 /* Index generation function */
1049 int caseIgnoreIA5Filter(
1050         unsigned flags,
1051         Syntax *syntax,
1052         MatchingRule *mr,
1053         struct berval *prefix,
1054         void * assertValue,
1055         struct berval ***keysp )
1056 {
1057         size_t slen, mlen;
1058         struct berval **keys;
1059         lutil_MD5_CTX   MD5context;
1060         unsigned char   MD5digest[LUTIL_MD5_BYTES];
1061         struct berval *value;
1062         struct berval digest;
1063         digest.bv_val = MD5digest;
1064         digest.bv_len = sizeof(MD5digest);
1065
1066         slen = strlen( syntax->ssyn_oid );
1067         mlen = strlen( mr->smr_oid );
1068
1069         value = ber_bvdup( (struct berval *) assertValue );
1070         ldap_pvt_str2upper( value->bv_val );
1071
1072         keys = ch_malloc( sizeof( struct berval * ) * 2 );
1073
1074         lutil_MD5Init( &MD5context );
1075         if( prefix != NULL && prefix->bv_len > 0 ) {
1076                 lutil_MD5Update( &MD5context,
1077                         prefix->bv_val, prefix->bv_len );
1078         }
1079         lutil_MD5Update( &MD5context,
1080                 syntax->ssyn_oid, slen );
1081         lutil_MD5Update( &MD5context,
1082                 mr->smr_oid, mlen );
1083         lutil_MD5Update( &MD5context,
1084                 value->bv_val, value->bv_len );
1085         lutil_MD5Final( MD5digest, &MD5context );
1086
1087         keys[0] = ber_bvdup( &digest );
1088         keys[1] = NULL;
1089
1090         ber_bvfree( value );
1091
1092         *keysp = keys;
1093         return LDAP_SUCCESS;
1094 }
1095
1096 static int
1097 numericStringNormalize(
1098         Syntax *syntax,
1099         struct berval *val,
1100         struct berval **normalized )
1101 {
1102         /* similiar to IA5StringNormalize except removes all spaces */
1103         struct berval *newval;
1104         char *p, *q;
1105
1106         newval = ch_malloc( sizeof( struct berval ) );
1107
1108         p = val->bv_val;
1109
1110         /* Ignore initial whitespace */
1111         while ( ASCII_SPACE( *p ) ) {
1112                 p++;
1113         }
1114
1115         if( *p != '\0' ) {
1116                 ch_free( newval );
1117                 return LDAP_INVALID_SYNTAX;
1118         }
1119
1120         newval->bv_val = ch_strdup( p );
1121         p = q = newval->bv_val;
1122
1123         while ( *p ) {
1124                 if ( ASCII_SPACE( *p ) ) {
1125                         /* Ignore whitespace */
1126                         p++;
1127                 } else {
1128                         *q++ = *p++;
1129                 }
1130         }
1131
1132         assert( *newval->bv_val );
1133         assert( newval->bv_val < p );
1134         assert( p <= q );
1135
1136         /* cannot start with a space */
1137         assert( !ASCII_SPACE(*newval->bv_val) );
1138
1139         /* cannot end with a space */
1140         assert( !ASCII_SPACE( q[-1] ) );
1141
1142         /* null terminate */
1143         *q = '\0';
1144
1145         newval->bv_len = q - newval->bv_val;
1146         *normalized = newval;
1147
1148         return LDAP_SUCCESS;
1149 }
1150
1151 static int
1152 objectIdentifierFirstComponentMatch(
1153         int *matchp,
1154         unsigned flags,
1155         Syntax *syntax,
1156         MatchingRule *mr,
1157         struct berval *value,
1158         void *assertedValue )
1159 {
1160         int rc = LDAP_SUCCESS;
1161         int match;
1162         struct berval *asserted = (struct berval *) assertedValue;
1163         ber_len_t i;
1164         struct berval oid;
1165
1166         if( value->bv_len == 0 || value->bv_val[0] != '(' /*')'*/ ) {
1167                 return LDAP_INVALID_SYNTAX;
1168         }
1169
1170         /* trim leading white space */
1171         for( i=1; ASCII_SPACE(value->bv_val[i]) && i < value->bv_len; i++ ) {
1172                 /* empty */
1173         }
1174
1175         /* grab next word */
1176         oid.bv_val = &value->bv_val[i];
1177         oid.bv_len = value->bv_len - i;
1178         for( i=1; ASCII_SPACE(value->bv_val[i]) && i < oid.bv_len; i++ ) {
1179                 /* empty */
1180         }
1181         oid.bv_len = i;
1182
1183         /* insert attributeTypes, objectclass check here */
1184         if( OID_LEADCHAR(asserted->bv_val[0]) ) {
1185                 rc = objectIdentifierMatch( &match, flags, syntax, mr, &oid, asserted );
1186
1187         } else {
1188                 char *stored = ch_malloc( oid.bv_len + 1 );
1189                 memcpy( stored, oid.bv_val, oid.bv_len );
1190                 stored[oid.bv_len] = '\0';
1191
1192                 if ( !strcmp( syntax->ssyn_oid, SLAP_SYNTAX_MATCHINGRULES_OID ) ) {
1193                         MatchingRule *asserted_mr = mr_find( asserted->bv_val );
1194                         MatchingRule *stored_mr = mr_find( stored );
1195
1196                         if( asserted_mr == NULL ) {
1197                                 rc = SLAPD_COMPARE_UNDEFINED;
1198                         } else {
1199                                 match = asserted_mr != stored_mr;
1200                         }
1201
1202                 } else if ( !strcmp( syntax->ssyn_oid,
1203                         SLAP_SYNTAX_ATTRIBUTETYPES_OID ) )
1204                 {
1205                         AttributeType *asserted_at = at_find( asserted->bv_val );
1206                         AttributeType *stored_at = at_find( stored );
1207
1208                         if( asserted_at == NULL ) {
1209                                 rc = SLAPD_COMPARE_UNDEFINED;
1210                         } else {
1211                                 match = asserted_at != stored_at;
1212                         }
1213
1214                 } else if ( !strcmp( syntax->ssyn_oid,
1215                         SLAP_SYNTAX_OBJECTCLASSES_OID ) )
1216                 {
1217                         ObjectClass *asserted_oc = oc_find( asserted->bv_val );
1218                         ObjectClass *stored_oc = oc_find( stored );
1219
1220                         if( asserted_oc == NULL ) {
1221                                 rc = SLAPD_COMPARE_UNDEFINED;
1222                         } else {
1223                                 match = asserted_oc != stored_oc;
1224                         }
1225                 }
1226
1227                 ch_free( stored );
1228         }
1229
1230         Debug( LDAP_DEBUG_ARGS, "objectIdentifierFirstComponentMatch "
1231                 "%d\n\t\"%s\"\n\t\"%s\"\n",
1232             match, value->bv_val, asserted->bv_val );
1233
1234         if( rc == LDAP_SUCCESS ) *matchp = match;
1235         return rc;
1236 }
1237
1238 static int
1239 check_time_syntax (struct berval *val,
1240         int start,
1241         int *parts)
1242 {
1243         static int ceiling[9] = { 99, 99, 11, 30, 23, 59, 59, 12, 59 };
1244         static int mdays[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1245         char *p, *e;
1246         int part, c, neg = 0;
1247
1248         if( val->bv_len == 0 )
1249                 return LDAP_INVALID_SYNTAX;
1250
1251         p = (char *)val->bv_val;
1252         e = p + val->bv_len;
1253
1254         /* Ignore initial whitespace */
1255         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
1256                 p++;
1257         }
1258
1259         if (e - p < 13 - (2 * start))
1260                 return LDAP_INVALID_SYNTAX;
1261
1262         for (part = 0; part < 9; part++)
1263                 parts[part] = 0;
1264
1265         for (part = start; part < 7; part++) {
1266                 c = *p;
1267                 if ((part == 6)
1268                         && (c == 'Z'
1269                                 || c == '+'
1270                                 || c == '-'))
1271                 {
1272                         part++;
1273                         break;
1274                 }
1275                 p++;
1276                 c -= '0';
1277                 if (p == e)
1278                         return LDAP_INVALID_SYNTAX;
1279                 if (c < 0 || c > 9)
1280                         return LDAP_INVALID_SYNTAX;
1281                 parts[part] = c;
1282
1283                 c = *p++ - '0';
1284                 if (p == e)
1285                         return LDAP_INVALID_SYNTAX;
1286                 if (c < 0 || c > 9)
1287                         return LDAP_INVALID_SYNTAX;
1288                 parts[part] *= 10;
1289                 parts[part] += c;
1290
1291                 if (part == 2 || part == 3)
1292                         parts[part]--;
1293                 if (parts[part] < 0)
1294                         return LDAP_INVALID_SYNTAX;
1295                 if (parts[part] > ceiling[part])
1296                         return LDAP_INVALID_SYNTAX;
1297         }
1298         if (parts[2] == 1) {
1299                 if (parts[3] > mdays[parts[2]])
1300                         return LDAP_INVALID_SYNTAX;
1301                 if (parts[1] & 0x03) {
1302                         /* FIXME:  This is an incomplete leap-year
1303                          * check that fails in 2100, 2200, 2300,
1304                          * 2500, 2600, 2700, ...
1305                          */
1306                         if (parts[3] > mdays[parts[2]] - 1)
1307                                 return LDAP_INVALID_SYNTAX;
1308                 }
1309         }
1310         c = *p++;
1311         if (c == 'Z') {
1312                 /* all done */
1313         } else if (c != '+' && c != '-') {
1314                 return LDAP_INVALID_SYNTAX;
1315         } else {
1316                 if (c == '-')
1317                         neg = 1;
1318                 if (p > e - 4)
1319                         return LDAP_INVALID_SYNTAX;
1320                 for (part = 7; part < 9; part++) {
1321                         c = *p++ - '0';
1322                         if (c < 0 || c > 9)
1323                                 return LDAP_INVALID_SYNTAX;
1324                         parts[part] = c;
1325
1326                         c = *p++ - '0';
1327                         if (c < 0 || c > 9)
1328                                 return LDAP_INVALID_SYNTAX;
1329                         parts[part] *= 10;
1330                         parts[part] += c;
1331                         if (parts[part] < 0 || parts[part] > ceiling[part])
1332                                 return LDAP_INVALID_SYNTAX;
1333                 }
1334         }
1335
1336         /* Ignore trailing whitespace */
1337         while ( ( p < e ) && ASCII_SPACE( *p ) ) {
1338                 p++;
1339         }
1340         if (p != e)
1341                 return LDAP_INVALID_SYNTAX;
1342
1343         if (neg == 0) {
1344                 parts[4] += parts[7];
1345                 parts[5] += parts[8];
1346                 for (part = 7; --part > 0; ) {
1347                         if (part != 3)
1348                                 c = ceiling[part];
1349                         else {
1350                                 /* FIXME:  This is an incomplete leap-year
1351                                  * check that fails in 2100, 2200, 2300,
1352                                  * 2500, 2600, 2700, ...
1353                                  */
1354                                 c = mdays[parts[2]];
1355                                 if (parts[2] == 1)
1356                                         c--;
1357                         }
1358                         if (parts[part] > c) {
1359                                 parts[part] -= c + 1;
1360                                 parts[part - 1]++;
1361                         }
1362                 }
1363         } else {
1364                 parts[4] -= parts[7];
1365                 parts[5] -= parts[8];
1366                 for (part = 7; --part > 0; ) {
1367                         if (part != 3)
1368                                 c = ceiling[part];
1369                         else {
1370                                 /* FIXME:  This is an incomplete leap-year
1371                                  * check that fails in 2100, 2200, 2300,
1372                                  * 2500, 2600, 2700, ...
1373                                  */
1374                                 c = mdays[(parts[2] - 1) % 12];
1375                                 if (parts[2] == 2)
1376                                         c--;
1377                         }
1378                         if (parts[part] < 0) {
1379                                 parts[part] += c + 1;
1380                                 parts[part - 1]--;
1381                         }
1382                 }
1383         }
1384
1385         return LDAP_SUCCESS;
1386 }
1387
1388 static int
1389 utcTimeNormalize(
1390         Syntax *syntax,
1391         struct berval *val,
1392         struct berval **normalized )
1393 {
1394         struct berval *out;
1395         int parts[9], rc;
1396
1397         rc = check_time_syntax(val, 1, parts);
1398         if (rc != LDAP_SUCCESS) {
1399                 return rc;
1400         }
1401
1402         *normalized = NULL;
1403         out = ch_malloc( sizeof(struct berval) );
1404         if( out == NULL )
1405                 return LBER_ERROR_MEMORY;
1406
1407         out->bv_val = ch_malloc( 14 );
1408         if ( out->bv_val == NULL ) {
1409                 ch_free( out );
1410                 return LBER_ERROR_MEMORY;
1411         }
1412
1413         sprintf( out->bv_val, "%02ld%02ld%02ld%02ld%02ld%02ldZ",
1414                                 parts[1], parts[2] + 1, parts[3] + 1,
1415                                 parts[4], parts[5], parts[6] );
1416         out->bv_len = 13;
1417         *normalized = out;
1418
1419         return LDAP_SUCCESS;
1420 }
1421
1422 static int
1423 utcTimeValidate(
1424         Syntax *syntax,
1425         struct berval *in )
1426 {
1427         int parts[9];
1428
1429         return check_time_syntax(in, 1, parts);
1430 }
1431
1432 static int
1433 generalizedTimeNormalize(
1434         Syntax *syntax,
1435         struct berval *val,
1436         struct berval **normalized )
1437 {
1438         struct berval *out;
1439         int parts[9], rc;
1440
1441         rc = check_time_syntax(val, 0, parts);
1442         if (rc != LDAP_SUCCESS) {
1443                 return rc;
1444         }
1445
1446         *normalized = NULL;
1447         out = ch_malloc( sizeof(struct berval) );
1448         if( out == NULL )
1449                 return LBER_ERROR_MEMORY;
1450
1451         out->bv_val = ch_malloc( 16 );
1452         if ( out->bv_val == NULL ) {
1453                 ch_free( out );
1454                 return LBER_ERROR_MEMORY;
1455         }
1456
1457         sprintf( out->bv_val, "%02ld%02ld%02ld%02ld%02ld%02ld%02ldZ",
1458                                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
1459                                 parts[4], parts[5], parts[6] );
1460         out->bv_len = 15;
1461         *normalized = out;
1462
1463         return LDAP_SUCCESS;
1464 }
1465
1466 static int
1467 generalizedTimeValidate(
1468         Syntax *syntax,
1469         struct berval *in )
1470 {
1471         int parts[9];
1472
1473         return check_time_syntax(in, 0, parts);
1474 }
1475
1476 struct syntax_defs_rec {
1477         char *sd_desc;
1478         int sd_flags;
1479         slap_syntax_validate_func *sd_validate;
1480         slap_syntax_transform_func *sd_normalize;
1481         slap_syntax_transform_func *sd_pretty;
1482 #ifdef SLAPD_BINARY_CONVERSION
1483         slap_syntax_transform_func *sd_ber2str;
1484         slap_syntax_transform_func *sd_str2ber;
1485 #endif
1486 };
1487
1488 #define X_HIDE "X-HIDE 'TRUE' "
1489 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
1490 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
1491
1492 struct syntax_defs_rec syntax_defs[] = {
1493         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' " X_BINARY X_NOT_H_R ")",
1494                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
1495         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
1496                 0, NULL, NULL, NULL},
1497         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
1498                 0, NULL, NULL, NULL},
1499         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' " X_NOT_H_R ")",
1500                 SLAP_SYNTAX_BLOB, blobValidate, NULL, NULL},
1501         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' " X_BINARY X_NOT_H_R ")",
1502                 SLAP_SYNTAX_BER, berValidate, NULL, NULL},
1503         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
1504                 0, bitStringValidate, bitStringNormalize, NULL },
1505         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
1506                 0, booleanValidate, booleanNormalize, booleanPretty},
1507         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
1508                 X_BINARY X_NOT_H_R ")",
1509                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
1510         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
1511                 X_BINARY X_NOT_H_R ")",
1512                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
1513         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
1514                 X_BINARY X_NOT_H_R ")",
1515                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
1516         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
1517                 0, NULL, NULL, NULL},
1518         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
1519                 0, dnValidate, dnNormalize, dnPretty},
1520         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
1521                 0, NULL, NULL, NULL},
1522         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
1523                 0, NULL, NULL, NULL},
1524         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
1525                 0, UTF8StringValidate, UTF8StringNormalize, NULL},
1526         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
1527                 0, NULL, NULL, NULL},
1528         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
1529                 0, NULL, NULL, NULL},
1530         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
1531                 0, NULL, NULL, NULL},
1532         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
1533                 0, NULL, NULL, NULL},
1534         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
1535                 0, NULL, NULL, NULL},
1536         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
1537                 0, IA5StringValidate, faxNumberNormalize, NULL},
1538         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
1539                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
1540         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
1541                 0, generalizedTimeValidate, generalizedTimeNormalize, NULL},
1542         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
1543                 0, NULL, NULL, NULL},
1544         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
1545                 0, IA5StringValidate, IA5StringNormalize, NULL},
1546         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
1547                 0, integerValidate, integerNormalize, integerPretty},
1548         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
1549                 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
1550         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
1551                 0, NULL, NULL, NULL},
1552         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
1553                 0, NULL, NULL, NULL},
1554         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
1555                 0, NULL, NULL, NULL},
1556         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
1557                 0, NULL, NULL, NULL},
1558         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
1559                 0, NULL, NULL, NULL},
1560         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
1561                 0, NULL, NULL, NULL},
1562         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
1563                 0, NULL, NULL, NULL},
1564         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
1565                 0, IA5StringValidate, numericStringNormalize, NULL},
1566         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
1567                 0, NULL, NULL, NULL},
1568         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
1569                 0, oidValidate, NULL, NULL},
1570         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
1571                 0, NULL, NULL, NULL},
1572         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
1573                 0, blobValidate, NULL, NULL},
1574         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
1575                 0, blobValidate, NULL, NULL},
1576         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
1577                 0, NULL, NULL, NULL},
1578         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
1579                 0, NULL, NULL, NULL},
1580         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
1581                 0, printableStringValidate, NULL, NULL},
1582         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
1583                 X_BINARY X_NOT_H_R ")",
1584                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL, NULL},
1585         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
1586                 0, IA5StringValidate, phoneNumberNormalize, NULL},
1587         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
1588                 0, NULL, NULL, NULL},
1589         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
1590                 0, IA5StringValidate, telexNumberNormalize, NULL},
1591         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
1592                 0, utcTimeValidate, utcTimeNormalize, NULL},
1593         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
1594                 0, NULL, NULL, NULL},
1595         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
1596                 0, NULL, NULL, NULL},
1597         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
1598                 0, NULL, NULL, NULL},
1599         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
1600                 0, NULL, NULL, NULL},
1601         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
1602                 0, NULL, NULL, NULL},
1603
1604         /* OpenLDAP Experimental Syntaxes */
1605         {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
1606                 0, IA5StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */, NULL, NULL},
1607         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
1608                 0, NULL, NULL, NULL},
1609         {"( 1.3.6.1.4.1.4203.666.2.3 DESC 'OpenLDAP void' " X_HIDE ")" ,
1610                 SLAP_SYNTAX_HIDE, inValidate, NULL, NULL},
1611 #if 0 /* not needed */
1612         {"( 1.3.6.1.4.1.4203.666.2.4 DESC 'OpenLDAP DN' " X_HIDE ")" ,
1613                 SLAP_SYNTAX_HIDE, inValidate, NULL, NULL},
1614 #endif
1615
1616         {NULL, 0, NULL, NULL, NULL}
1617 };
1618
1619 struct mrule_defs_rec {
1620         char *                                          mrd_desc;
1621         unsigned                                        mrd_usage;
1622         slap_mr_convert_func *          mrd_convert;
1623         slap_mr_normalize_func *        mrd_normalize;
1624         slap_mr_match_func *            mrd_match;
1625         slap_mr_indexer_func *          mrd_indexer;
1626         slap_mr_filter_func *           mrd_filter;
1627 };
1628
1629 /*
1630  * Other matching rules in X.520 that we do not use:
1631  *
1632  * 2.5.13.9             numericStringOrderingMatch
1633  * 2.5.13.13    booleanMatch
1634  * 2.5.13.15    integerOrderingMatch
1635  * 2.5.13.18    octetStringOrderingMatch
1636  * 2.5.13.19    octetStringSubstringsMatch
1637  * 2.5.13.25    uTCTimeMatch
1638  * 2.5.13.26    uTCTimeOrderingMatch
1639  * 2.5.13.31    directoryStringFirstComponentMatch
1640  * 2.5.13.32    wordMatch
1641  * 2.5.13.33    keywordMatch
1642  * 2.5.13.34    certificateExactMatch
1643  * 2.5.13.35    certificateMatch
1644  * 2.5.13.36    certificatePairExactMatch
1645  * 2.5.13.37    certificatePairMatch
1646  * 2.5.13.38    certificateListExactMatch
1647  * 2.5.13.39    certificateListMatch
1648  * 2.5.13.40    algorithmIdentifierMatch
1649  * 2.5.13.41    storedPrefixMatch
1650  * 2.5.13.42    attributeCertificateMatch
1651  * 2.5.13.43    readerAndKeyIDMatch
1652  * 2.5.13.44    attributeIntegrityMatch
1653  */
1654
1655 struct mrule_defs_rec mrule_defs[] = {
1656         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
1657                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
1658                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
1659                 NULL, NULL, objectIdentifierMatch,
1660                 caseIgnoreIA5Indexer, caseIgnoreIA5Filter},
1661
1662         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
1663                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
1664                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
1665                 NULL, NULL, dnMatch, dnIndexer, dnFilter},
1666
1667         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
1668                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
1669                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
1670                 NULL, NULL, caseIgnoreMatch, caseIgnoreIndexer, caseIgnoreFilter},
1671
1672         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
1673                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
1674                 SLAP_MR_ORDERING,
1675                 NULL, NULL, caseIgnoreOrderingMatch, NULL, NULL},
1676
1677         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
1678                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
1679                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
1680                 NULL, NULL, caseIgnoreSubstringsMatch,
1681                 caseIgnoreSubstringsIndexer, caseIgnoreSubstringsFilter},
1682
1683         /* Next three are not in the RFC's, but are needed for compatibility */
1684         {"( 2.5.13.5 NAME 'caseExactMatch' "
1685                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
1686                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
1687                 NULL, NULL, caseExactMatch, caseExactIndexer, caseExactFilter},
1688
1689         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
1690                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
1691                 SLAP_MR_ORDERING,
1692                 NULL, NULL, caseExactOrderingMatch, NULL, NULL},
1693
1694         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
1695                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
1696                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
1697                 NULL, NULL, caseExactSubstringsMatch,
1698                 caseExactSubstringsIndexer, caseExactSubstringsFilter},
1699
1700         {"( 2.5.13.8 NAME 'numericStringMatch' "
1701                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
1702                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
1703                 NULL, NULL, caseIgnoreIA5Match, NULL, NULL},
1704
1705         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
1706                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
1707                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
1708                 NULL, NULL, caseIgnoreIA5SubstringsMatch,
1709                 caseIgnoreIA5SubstringsIndexer, caseIgnoreIA5SubstringsFilter},
1710
1711         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
1712                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
1713                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
1714                 NULL, NULL, caseIgnoreListMatch, NULL, NULL},
1715
1716         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
1717                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
1718                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
1719                 NULL, NULL, caseIgnoreListSubstringsMatch, NULL, NULL},
1720
1721         {"( 2.5.13.14 NAME 'integerMatch' "
1722                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
1723                 SLAP_MR_NONE | SLAP_MR_EXT,
1724                 NULL, NULL, integerMatch, NULL, NULL},
1725
1726         {"( 2.5.13.16 NAME 'bitStringMatch' "
1727                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
1728                 SLAP_MR_NONE | SLAP_MR_EXT,
1729                 NULL, NULL, bitStringMatch, NULL, NULL},
1730
1731         {"( 2.5.13.17 NAME 'octetStringMatch' "
1732                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
1733                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
1734                 NULL, NULL, octetStringMatch, octetStringIndexer, octetStringFilter},
1735
1736         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
1737                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
1738                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
1739                 NULL, NULL, telephoneNumberMatch, NULL, NULL},
1740
1741         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
1742                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
1743                 SLAP_MR_SUBSTR | SLAP_MR_EXT,
1744                 NULL, NULL, telephoneNumberSubstringsMatch, NULL, NULL},
1745
1746         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
1747                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
1748                 SLAP_MR_NONE | SLAP_MR_EXT,
1749                 NULL, NULL, presentationAddressMatch, NULL, NULL},
1750
1751         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
1752                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
1753                 SLAP_MR_NONE | SLAP_MR_EXT,
1754                 NULL, NULL, uniqueMemberMatch, NULL, NULL},
1755
1756         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
1757                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
1758                 SLAP_MR_NONE | SLAP_MR_EXT,
1759                 NULL, NULL, protocolInformationMatch, NULL, NULL},
1760
1761         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
1762                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
1763                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
1764                 NULL, NULL, generalizedTimeMatch, NULL, NULL},
1765
1766         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
1767                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
1768                 SLAP_MR_ORDERING,
1769                 NULL, NULL, generalizedTimeOrderingMatch, NULL, NULL},
1770
1771         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
1772                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
1773                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
1774                 NULL, NULL, integerFirstComponentMatch, NULL, NULL},
1775
1776         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
1777                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
1778                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
1779                 NULL, NULL, objectIdentifierFirstComponentMatch, NULL, NULL},
1780
1781         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
1782                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
1783                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
1784                 NULL, NULL, caseExactIA5Match, caseExactIA5Indexer, caseExactIA5Filter},
1785
1786         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
1787                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
1788                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
1789                 NULL, NULL, caseIgnoreIA5Match, caseExactIA5Indexer, caseExactIA5Filter},
1790
1791         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
1792                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
1793                 SLAP_MR_SUBSTR,
1794                 NULL, NULL, caseIgnoreIA5SubstringsMatch,
1795                 caseIgnoreIA5SubstringsIndexer, caseIgnoreIA5SubstringsFilter},
1796
1797         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
1798                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
1799                 SLAP_MR_EQUALITY,
1800                 NULL, NULL, authPasswordMatch, NULL, NULL},
1801
1802         {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
1803                 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
1804                 SLAP_MR_EQUALITY,
1805                 NULL, NULL, OpenLDAPaciMatch, NULL, NULL},
1806
1807         {NULL, SLAP_MR_NONE, NULL, NULL, NULL}
1808 };
1809
1810 int
1811 schema_init( void )
1812 {
1813         int             res;
1814         int             i;
1815
1816         /* we should only be called once (from main) */
1817         assert( schema_init_done == 0 );
1818
1819         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
1820                 res = register_syntax( syntax_defs[i].sd_desc,
1821                     syntax_defs[i].sd_flags,
1822                     syntax_defs[i].sd_validate,
1823                     syntax_defs[i].sd_normalize,
1824                         syntax_defs[i].sd_pretty
1825 #ifdef SLAPD_BINARY_CONVERSION
1826                         ,
1827                     syntax_defs[i].sd_ber2str,
1828                         syntax_defs[i].sd_str2ber
1829 #endif
1830                 );
1831
1832                 if ( res ) {
1833                         fprintf( stderr, "schema_init: Error registering syntax %s\n",
1834                                  syntax_defs[i].sd_desc );
1835                         return LDAP_OTHER;
1836                 }
1837         }
1838
1839         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
1840                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE ) {
1841                         fprintf( stderr,
1842                                 "schema_init: Ingoring unusable matching rule %s\n",
1843                                  mrule_defs[i].mrd_desc );
1844                         continue;
1845                 }
1846
1847                 res = register_matching_rule(
1848                         mrule_defs[i].mrd_desc,
1849                         mrule_defs[i].mrd_usage,
1850                         mrule_defs[i].mrd_convert,
1851                         mrule_defs[i].mrd_normalize,
1852                     mrule_defs[i].mrd_match,
1853                         mrule_defs[i].mrd_indexer,
1854                         mrule_defs[i].mrd_filter );
1855
1856                 if ( res ) {
1857                         fprintf( stderr,
1858                                 "schema_init: Error registering matching rule %s\n",
1859                                  mrule_defs[i].mrd_desc );
1860                         return LDAP_OTHER;
1861                 }
1862         }
1863         schema_init_done = 1;
1864         return LDAP_SUCCESS;
1865 }