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