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