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