]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
0cb230945db8ef303f08cd7975287a490ddafd0f
[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                 return LDAP_INVALID_SYNTAX;
1295         }
1296
1297         return LDAP_SUCCESS;
1298 }
1299
1300 static int
1301 numericoidValidate(
1302         Syntax *syntax,
1303         struct berval *in )
1304 {
1305         struct berval val = *in;
1306
1307         if( val.bv_len == 0 ) {
1308                 /* disallow empty strings */
1309                 return LDAP_INVALID_SYNTAX;
1310         }
1311
1312         while( OID_LEADCHAR( val.bv_val[0] ) ) {
1313                 if ( val.bv_len == 1 ) {
1314                         return LDAP_SUCCESS;
1315                 }
1316
1317                 if ( val.bv_val[0] == '0' ) {
1318                         break;
1319                 }
1320
1321                 val.bv_val++;
1322                 val.bv_len--;
1323
1324                 while ( OID_LEADCHAR( val.bv_val[0] )) {
1325                         val.bv_val++;
1326                         val.bv_len--;
1327
1328                         if ( val.bv_len == 0 ) {
1329                                 return LDAP_SUCCESS;
1330                         }
1331                 }
1332
1333                 if( !OID_SEPARATOR( val.bv_val[0] )) {
1334                         break;
1335                 }
1336
1337                 val.bv_val++;
1338                 val.bv_len--;
1339         }
1340
1341         return LDAP_INVALID_SYNTAX;
1342 }
1343
1344 static int
1345 integerValidate(
1346         Syntax *syntax,
1347         struct berval *in )
1348 {
1349         ber_len_t i;
1350         struct berval val = *in;
1351
1352         if( val.bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1353
1354         if ( val.bv_val[0] == '-' ) {
1355                 val.bv_len--;
1356                 val.bv_val++;
1357
1358                 if( val.bv_len == 0 ) { /* bare "-" */
1359                         return LDAP_INVALID_SYNTAX;
1360                 }
1361
1362                 if( val.bv_val[0] == '0' ) { /* "-0" */
1363                         return LDAP_INVALID_SYNTAX;
1364                 }
1365
1366         } else if ( val.bv_val[0] == '0' ) {
1367                 if( val.bv_len > 1 ) { /* "0<more>" */
1368                         return LDAP_INVALID_SYNTAX;
1369                 }
1370
1371                 return LDAP_SUCCESS;
1372         }
1373
1374         for( i=0; i < val.bv_len; i++ ) {
1375                 if( !ASCII_DIGIT(val.bv_val[i]) ) {
1376                         return LDAP_INVALID_SYNTAX;
1377                 }
1378         }
1379
1380         return LDAP_SUCCESS;
1381 }
1382
1383 static int
1384 integerMatch(
1385         int *matchp,
1386         slap_mask_t flags,
1387         Syntax *syntax,
1388         MatchingRule *mr,
1389         struct berval *value,
1390         void *assertedValue )
1391 {
1392         struct berval *asserted = (struct berval *) assertedValue;
1393         int vsign = 1, asign = 1;       /* default sign = '+' */
1394         struct berval v, a;
1395         int match;
1396
1397         v = *value;
1398         if( v.bv_val[0] == '-' ) {
1399                 vsign = -1;
1400                 v.bv_val++;
1401                 v.bv_len--;
1402         }
1403
1404         if( v.bv_len == 0 ) vsign = 0;
1405
1406         a = *asserted;
1407         if( a.bv_val[0] == '-' ) {
1408                 asign = -1;
1409                 a.bv_val++;
1410                 a.bv_len--;
1411         }
1412
1413         if( a.bv_len == 0 ) vsign = 0;
1414
1415         match = vsign - asign;
1416         if( match == 0 ) {
1417                 match = ( v.bv_len != a.bv_len
1418                         ? ( v.bv_len < a.bv_len ? -1 : 1 )
1419                         : memcmp( v.bv_val, a.bv_val, v.bv_len ));
1420                 if( vsign < 0 ) match = -match;
1421         }
1422
1423         *matchp = match;
1424         return LDAP_SUCCESS;
1425 }
1426         
1427 static int
1428 countryStringValidate(
1429         Syntax *syntax,
1430         struct berval *val )
1431 {
1432         if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
1433
1434         if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
1435                 return LDAP_INVALID_SYNTAX;
1436         }
1437         if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
1438                 return LDAP_INVALID_SYNTAX;
1439         }
1440
1441         return LDAP_SUCCESS;
1442 }
1443
1444 static int
1445 printableStringValidate(
1446         Syntax *syntax,
1447         struct berval *val )
1448 {
1449         ber_len_t i;
1450
1451         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1452
1453         for(i=0; i < val->bv_len; i++) {
1454                 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
1455                         return LDAP_INVALID_SYNTAX;
1456                 }
1457         }
1458
1459         return LDAP_SUCCESS;
1460 }
1461
1462 static int
1463 printablesStringValidate(
1464         Syntax *syntax,
1465         struct berval *val )
1466 {
1467         ber_len_t i, len;
1468
1469         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1470
1471         for(i=0,len=0; i < val->bv_len; i++) {
1472                 int c = val->bv_val[i];
1473
1474                 if( c == '$' ) {
1475                         if( len == 0 ) {
1476                                 return LDAP_INVALID_SYNTAX;
1477                         }
1478                         len = 0;
1479
1480                 } else if ( SLAP_PRINTABLE(c) ) {
1481                         len++;
1482                 } else {
1483                         return LDAP_INVALID_SYNTAX;
1484                 }
1485         }
1486
1487         if( len == 0 ) {
1488                 return LDAP_INVALID_SYNTAX;
1489         }
1490
1491         return LDAP_SUCCESS;
1492 }
1493
1494 static int
1495 IA5StringValidate(
1496         Syntax *syntax,
1497         struct berval *val )
1498 {
1499         ber_len_t i;
1500
1501         if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1502
1503         for(i=0; i < val->bv_len; i++) {
1504                 if( !LDAP_ASCII(val->bv_val[i]) ) {
1505                         return LDAP_INVALID_SYNTAX;
1506                 }
1507         }
1508
1509         return LDAP_SUCCESS;
1510 }
1511
1512 static int
1513 IA5StringNormalize(
1514         slap_mask_t use,
1515         Syntax *syntax,
1516         MatchingRule *mr,
1517         struct berval *val,
1518         struct berval *normalized,
1519         void *ctx )
1520 {
1521         char *p, *q;
1522         int casefold = SLAP_MR_ASSOCIATED(mr, slap_schema.si_mr_caseExactIA5Match);
1523
1524         assert( val->bv_len );
1525
1526         p = val->bv_val;
1527
1528         /* Ignore initial whitespace */
1529         while ( ASCII_SPACE( *p ) ) p++;
1530
1531         normalized->bv_val = ber_strdup_x( p, ctx );
1532         p = q = normalized->bv_val;
1533
1534         while ( *p ) {
1535                 if ( ASCII_SPACE( *p ) ) {
1536                         *q++ = *p++;
1537
1538                         /* Ignore the extra whitespace */
1539                         while ( ASCII_SPACE( *p ) ) {
1540                                 p++;
1541                         }
1542
1543                 } else if ( casefold ) {
1544                         /* Most IA5 rules require casefolding */
1545                         *q++ = TOLOWER(*p++);
1546
1547                 } else {
1548                         *q++ = *p++;
1549                 }
1550         }
1551
1552         assert( normalized->bv_val <= p );
1553         assert( q <= p );
1554
1555         /*
1556          * If the string ended in space, backup the pointer one
1557          * position.  One is enough because the above loop collapsed
1558          * all whitespace to a single space.
1559          */
1560         if ( ASCII_SPACE( q[-1] ) ) --q;
1561
1562         /* null terminate */
1563         *q = '\0';
1564
1565         normalized->bv_len = q - normalized->bv_val;
1566         if( normalized->bv_len == 0 ) {
1567                 normalized->bv_val = sl_realloc( normalized->bv_val, 2, ctx );
1568                 normalized->bv_val[0] = ' ';
1569                 normalized->bv_val[1] = '\0';
1570                 normalized->bv_len = 1;
1571         }
1572
1573         return LDAP_SUCCESS;
1574 }
1575
1576 static int
1577 numericStringValidate(
1578         Syntax *syntax,
1579         struct berval *in )
1580 {
1581         ber_len_t i;
1582
1583         if( in->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
1584
1585         for(i=0; i < in->bv_len; i++) {
1586                 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
1587                         return LDAP_INVALID_SYNTAX;
1588                 }
1589         }
1590
1591         return LDAP_SUCCESS;
1592 }
1593
1594 static int
1595 numericStringNormalize(
1596         slap_mask_t usage,
1597         Syntax *syntax,
1598         MatchingRule *mr,
1599         struct berval *val,
1600         struct berval *normalized,
1601         void *ctx )
1602 {
1603         /* removal all spaces */
1604         char *p, *q;
1605
1606         assert( val->bv_len );
1607
1608         normalized->bv_val = sl_malloc( val->bv_len + 1, ctx );
1609
1610         p = val->bv_val;
1611         q = normalized->bv_val;
1612
1613         while ( *p ) {
1614                 if ( ASCII_SPACE( *p ) ) {
1615                         /* Ignore whitespace */
1616                         p++;
1617                 } else {
1618                         *q++ = *p++;
1619                 }
1620         }
1621
1622         /* we should have copied no more then is in val */
1623         assert( (q - normalized->bv_val) <= (p - val->bv_val) );
1624
1625         /* null terminate */
1626         *q = '\0';
1627
1628         normalized->bv_len = q - normalized->bv_val;
1629
1630         if( normalized->bv_len == 0 ) {
1631                 normalized->bv_val = sl_realloc( normalized->bv_val, 2, ctx );
1632                 normalized->bv_val[0] = ' ';
1633                 normalized->bv_val[1] = '\0';
1634                 normalized->bv_len = 1;
1635         }
1636
1637         return LDAP_SUCCESS;
1638 }
1639
1640 static int
1641 integerBitAndMatch(
1642         int *matchp,
1643         slap_mask_t flags,
1644         Syntax *syntax,
1645         MatchingRule *mr,
1646         struct berval *value,
1647         void *assertedValue )
1648 {
1649         long lValue, lAssertedValue;
1650
1651         /* safe to assume integers are NUL terminated? */
1652         lValue = strtol(value->bv_val, NULL, 10);
1653         if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE ) {
1654                 return LDAP_CONSTRAINT_VIOLATION;
1655         }
1656
1657         lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
1658         if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX)
1659                 && errno == ERANGE )
1660         {
1661                 return LDAP_CONSTRAINT_VIOLATION;
1662         }
1663
1664         *matchp = (lValue & lAssertedValue) ? 0 : 1;
1665         return LDAP_SUCCESS;
1666 }
1667
1668 static int
1669 integerBitOrMatch(
1670         int *matchp,
1671         slap_mask_t flags,
1672         Syntax *syntax,
1673         MatchingRule *mr,
1674         struct berval *value,
1675         void *assertedValue )
1676 {
1677         long lValue, lAssertedValue;
1678
1679         /* safe to assume integers are NUL terminated? */
1680         lValue = strtol(value->bv_val, NULL, 10);
1681         if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE ) {
1682                 return LDAP_CONSTRAINT_VIOLATION;
1683         }
1684
1685         lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
1686         if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX)
1687                 && errno == ERANGE )
1688         {
1689                 return LDAP_CONSTRAINT_VIOLATION;
1690         }
1691
1692         *matchp = (lValue | lAssertedValue) ? 0 : -1;
1693         return LDAP_SUCCESS;
1694 }
1695
1696 static int
1697 serialNumberAndIssuerValidate(
1698         Syntax *syntax,
1699         struct berval *in )
1700 {
1701         int rc = LDAP_INVALID_SYNTAX;
1702         struct berval serialNumber, issuer;
1703
1704         serialNumber.bv_val = in->bv_val;
1705         for( serialNumber.bv_len = 0;
1706                 serialNumber.bv_len < in->bv_len;
1707                 serialNumber.bv_len++ )
1708         {
1709                 if ( serialNumber.bv_val[serialNumber.bv_len] == '$' ) {
1710                         issuer.bv_val = &serialNumber.bv_val[serialNumber.bv_len+1];
1711                         issuer.bv_len = in->bv_len - (serialNumber.bv_len+1);
1712
1713                         if( serialNumber.bv_len == 0 || issuer.bv_len == 0 ) break;
1714
1715                         rc = integerValidate( NULL, &serialNumber );
1716                         if( rc ) break;
1717
1718                         rc = dnValidate( NULL, &issuer );
1719                         break;
1720                 }
1721         }
1722
1723         return rc;
1724 }
1725
1726 static int
1727 serialNumberAndIssuerNormalize(
1728         slap_mask_t usage,
1729         Syntax *syntax,
1730         MatchingRule *mr,
1731         struct berval *val,
1732         struct berval *normalized,
1733         void *ctx )
1734 {
1735         int rc = LDAP_INVALID_SYNTAX;
1736         struct berval serialNumber, issuer, nissuer;
1737
1738         serialNumber.bv_val = val->bv_val;
1739         for( serialNumber.bv_len = 0;
1740                 serialNumber.bv_len < val->bv_len;
1741                 serialNumber.bv_len++ )
1742         {
1743                 if ( serialNumber.bv_val[serialNumber.bv_len] == '$' ) {
1744                         issuer.bv_val = &serialNumber.bv_val[serialNumber.bv_len+1];
1745                         issuer.bv_len = val->bv_len - (serialNumber.bv_len+1);
1746
1747                         if( serialNumber.bv_len == 0 || issuer.bv_len == 0 ) break;
1748
1749                         rc = dnNormalize( usage, syntax, mr, &issuer, &nissuer, ctx );
1750                         if( rc ) break;
1751
1752                         normalized->bv_len = serialNumber.bv_len + 1 + nissuer.bv_len;
1753                         normalized->bv_val = ch_malloc( normalized->bv_len + 1);
1754
1755                         AC_MEMCPY( normalized->bv_val,
1756                                 serialNumber.bv_val, serialNumber.bv_len );
1757                         normalized->bv_val[serialNumber.bv_len] = '$';
1758                         AC_MEMCPY( &normalized->bv_val[serialNumber.bv_len+1],
1759                                 nissuer.bv_val, nissuer.bv_len );
1760                         normalized->bv_val[normalized->bv_len] = '\0';
1761                         break;
1762                 }
1763         }
1764
1765         return rc;
1766 }
1767
1768 #ifdef HAVE_TLS
1769 #include <openssl/x509.h>
1770 #include <openssl/err.h>
1771
1772 /*
1773  * Next function returns a string representation of a ASN1_INTEGER.
1774  * It works for unlimited lengths.
1775  */
1776
1777 static struct berval *
1778 asn1_integer2str(ASN1_INTEGER *a, struct berval *bv)
1779 {
1780         char buf[256];
1781         char *p;
1782         static char digit[] = "0123456789";
1783   
1784         /* We work backwards, make it fill from the end of buf */
1785         p = buf + sizeof(buf) - 1;
1786         *p = '\0';
1787
1788         if ( a == NULL || a->length == 0 ) {
1789                 *--p = '0';
1790         } else {
1791                 int i;
1792                 int n = a->length;
1793                 int base = 0;
1794                 unsigned int *copy;
1795
1796                 /* We want to preserve the original */
1797                 copy = ch_malloc(n*sizeof(unsigned int));
1798                 for (i = 0; i<n; i++) {
1799                         copy[i] = a->data[i];
1800                 }
1801
1802                 /* 
1803                  * base indicates the index of the most significant
1804                  * byte that might be nonzero.  When it goes off the
1805                  * end, we now there is nothing left to do.
1806                  */
1807                 while (base < n) {
1808                         unsigned int carry;
1809
1810                         carry = 0;
1811                         for (i = base; i<n; i++ ) {
1812                                 copy[i] += carry*256;
1813                                 carry = copy[i] % 10;
1814                                 copy[i] /= 10;
1815                         }
1816                         if (p <= buf+1) {
1817                                 /*
1818                                  * Way too large, we need to leave
1819                                  * room for sign if negative
1820                                  */
1821                                 free(copy);
1822                                 return NULL;
1823                         }
1824                         *--p = digit[carry];
1825
1826                         if (copy[base] == 0) base++;
1827                 }
1828                 free(copy);
1829         }
1830
1831         if ( a->type == V_ASN1_NEG_INTEGER ) {
1832                 *--p = '-';
1833         }
1834
1835         return ber_str2bv( p, 0, 1, bv );
1836 }
1837
1838 /*
1839  * Given a certificate in DER format, extract the corresponding
1840  * assertion value for certificateExactMatch
1841  */
1842 static int
1843 certificateExactConvert(
1844         struct berval * in,
1845         struct berval * out )
1846 {
1847         int rc;
1848         X509 *xcert;
1849         unsigned char *p = in->bv_val;
1850         struct berval serial;
1851         struct berval issuer_dn;
1852
1853         xcert = d2i_X509(NULL, &p, in->bv_len);
1854         if ( !xcert ) {
1855 #ifdef NEW_LOGGING
1856                 LDAP_LOG( CONFIG, ENTRY, 
1857                         "certificateExactConvert: error parsing cert: %s\n",
1858                         ERR_error_string(ERR_get_error(),NULL), 0, 0 );
1859 #else
1860                 Debug( LDAP_DEBUG_ARGS, "certificateExactConvert: "
1861                        "error parsing cert: %s\n",
1862                        ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
1863 #endif
1864                 return LDAP_INVALID_SYNTAX;
1865         }
1866
1867         if ( !asn1_integer2str(xcert->cert_info->serialNumber, &serial) ) {
1868                 X509_free(xcert);
1869                 return LDAP_INVALID_SYNTAX;
1870         }
1871
1872         rc = dnX509normalize(X509_get_issuer_name(xcert), &issuer_dn );
1873         if( rc != LDAP_SUCCESS ) {
1874                 X509_free(xcert);
1875                 ber_memfree(serial.bv_val);
1876                 return LDAP_INVALID_SYNTAX;
1877         }
1878
1879         X509_free(xcert);
1880
1881         out->bv_len = serial.bv_len + issuer_dn.bv_len + sizeof(" $ ");
1882         out->bv_val = ch_malloc(out->bv_len);
1883         p = out->bv_val;
1884         AC_MEMCPY(p, serial.bv_val, serial.bv_len);
1885         p += serial.bv_len;
1886         AC_MEMCPY(p, " $ ", sizeof(" $ ")-1);
1887         p += 3;
1888         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
1889         p += issuer_dn.bv_len;
1890         *p++ = '\0';
1891
1892 #ifdef NEW_LOGGING
1893         LDAP_LOG( CONFIG, ARGS, 
1894                 "certificateExactConvert: \n    %s\n", out->bv_val, 0, 0 );
1895 #else
1896         Debug( LDAP_DEBUG_ARGS, "certificateExactConvert "
1897                 "\n\t\"%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( 16, 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_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_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 }