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