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