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