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