]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
ITS#2497, implement value-level ACLs:
[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 static int
1791 integerBitAndMatch(
1792         int *matchp,
1793         slap_mask_t flags,
1794         Syntax *syntax,
1795         MatchingRule *mr,
1796         struct berval *value,
1797         void *assertedValue )
1798 {
1799         long lValue, lAssertedValue;
1800
1801         /* safe to assume integers are NUL terminated? */
1802         lValue = strtol(value->bv_val, NULL, 10);
1803         if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE ) {
1804                 return LDAP_CONSTRAINT_VIOLATION;
1805         }
1806
1807         lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
1808         if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX)
1809                 && errno == ERANGE )
1810         {
1811                 return LDAP_CONSTRAINT_VIOLATION;
1812         }
1813
1814         *matchp = (lValue & lAssertedValue) ? 0 : 1;
1815         return LDAP_SUCCESS;
1816 }
1817
1818 static int
1819 integerBitOrMatch(
1820         int *matchp,
1821         slap_mask_t flags,
1822         Syntax *syntax,
1823         MatchingRule *mr,
1824         struct berval *value,
1825         void *assertedValue )
1826 {
1827         long lValue, lAssertedValue;
1828
1829         /* safe to assume integers are NUL terminated? */
1830         lValue = strtol(value->bv_val, NULL, 10);
1831         if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE ) {
1832                 return LDAP_CONSTRAINT_VIOLATION;
1833         }
1834
1835         lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
1836         if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX)
1837                 && errno == ERANGE )
1838         {
1839                 return LDAP_CONSTRAINT_VIOLATION;
1840         }
1841
1842         *matchp = (lValue | lAssertedValue) ? 0 : -1;
1843         return LDAP_SUCCESS;
1844 }
1845
1846 static int
1847 serialNumberAndIssuerValidate(
1848         Syntax *syntax,
1849         struct berval *in )
1850 {
1851         int rc = LDAP_INVALID_SYNTAX;
1852         struct berval serialNumber, issuer;
1853
1854         serialNumber.bv_val = in->bv_val;
1855         for( serialNumber.bv_len = 0;
1856                 serialNumber.bv_len < in->bv_len;
1857                 serialNumber.bv_len++ )
1858         {
1859                 if ( serialNumber.bv_val[serialNumber.bv_len] == '$' ) {
1860                         issuer.bv_val = &serialNumber.bv_val[serialNumber.bv_len+1];
1861                         issuer.bv_len = in->bv_len - (serialNumber.bv_len+1);
1862
1863                         if( serialNumber.bv_len == 0 || issuer.bv_len == 0 ) break;
1864
1865                         rc = integerValidate( NULL, &serialNumber );
1866                         if( rc ) break;
1867
1868                         rc = dnValidate( NULL, &issuer );
1869                         break;
1870                 }
1871         }
1872
1873         return rc;
1874 }
1875
1876 static int
1877 serialNumberAndIssuerNormalize(
1878         slap_mask_t usage,
1879         Syntax *syntax,
1880         MatchingRule *mr,
1881         struct berval *val,
1882         struct berval *normalized,
1883         void *ctx )
1884 {
1885         int rc = LDAP_INVALID_SYNTAX;
1886         struct berval serialNumber, issuer, nissuer;
1887
1888         serialNumber.bv_val = val->bv_val;
1889         for( serialNumber.bv_len = 0;
1890                 serialNumber.bv_len < val->bv_len;
1891                 serialNumber.bv_len++ )
1892         {
1893                 if ( serialNumber.bv_val[serialNumber.bv_len] == '$' ) {
1894                         issuer.bv_val = &serialNumber.bv_val[serialNumber.bv_len+1];
1895                         issuer.bv_len = val->bv_len - (serialNumber.bv_len+1);
1896
1897                         if( serialNumber.bv_len == 0 || issuer.bv_len == 0 ) break;
1898
1899                         rc = dnNormalize( usage, syntax, mr, &issuer, &nissuer, ctx );
1900                         if( rc ) break;
1901
1902                         normalized->bv_len = serialNumber.bv_len + 1 + nissuer.bv_len;
1903                         normalized->bv_val = ch_malloc( normalized->bv_len + 1);
1904
1905                         AC_MEMCPY( normalized->bv_val,
1906                                 serialNumber.bv_val, serialNumber.bv_len );
1907                         normalized->bv_val[serialNumber.bv_len] = '$';
1908                         AC_MEMCPY( &normalized->bv_val[serialNumber.bv_len+1],
1909                                 nissuer.bv_val, nissuer.bv_len );
1910                         normalized->bv_val[normalized->bv_len] = '\0';
1911                         break;
1912                 }
1913         }
1914
1915         return rc;
1916 }
1917
1918 #ifdef HAVE_TLS
1919 #include <openssl/x509.h>
1920 #include <openssl/err.h>
1921
1922 /*
1923  * Next function returns a string representation of a ASN1_INTEGER.
1924  * It works for unlimited lengths.
1925  */
1926
1927 static struct berval *
1928 asn1_integer2str(ASN1_INTEGER *a, struct berval *bv)
1929 {
1930         char buf[256];
1931         char *p;
1932         static char digit[] = "0123456789";
1933   
1934         /* We work backwards, make it fill from the end of buf */
1935         p = buf + sizeof(buf) - 1;
1936         *p = '\0';
1937
1938         if ( a == NULL || a->length == 0 ) {
1939                 *--p = '0';
1940         } else {
1941                 int i;
1942                 int n = a->length;
1943                 int base = 0;
1944                 unsigned int *copy;
1945
1946                 /* We want to preserve the original */
1947                 copy = ch_malloc(n*sizeof(unsigned int));
1948                 for (i = 0; i<n; i++) {
1949                         copy[i] = a->data[i];
1950                 }
1951
1952                 /* 
1953                  * base indicates the index of the most significant
1954                  * byte that might be nonzero.  When it goes off the
1955                  * end, we now there is nothing left to do.
1956                  */
1957                 while (base < n) {
1958                         unsigned int carry;
1959
1960                         carry = 0;
1961                         for (i = base; i<n; i++ ) {
1962                                 copy[i] += carry*256;
1963                                 carry = copy[i] % 10;
1964                                 copy[i] /= 10;
1965                         }
1966                         if (p <= buf+1) {
1967                                 /*
1968                                  * Way too large, we need to leave
1969                                  * room for sign if negative
1970                                  */
1971                                 free(copy);
1972                                 return NULL;
1973                         }
1974                         *--p = digit[carry];
1975
1976                         if (copy[base] == 0) base++;
1977                 }
1978                 free(copy);
1979         }
1980
1981         if ( a->type == V_ASN1_NEG_INTEGER ) {
1982                 *--p = '-';
1983         }
1984
1985         return ber_str2bv( p, 0, 1, bv );
1986 }
1987
1988 /*
1989  * Given a certificate in DER format, extract the corresponding
1990  * assertion value for certificateExactMatch
1991  */
1992 static int
1993 certificateExactConvert(
1994         struct berval * in,
1995         struct berval * out )
1996 {
1997         int rc;
1998         X509 *xcert;
1999         unsigned char *p = in->bv_val;
2000         struct berval serial;
2001         struct berval issuer_dn;
2002
2003         xcert = d2i_X509(NULL, &p, in->bv_len);
2004         if ( !xcert ) {
2005 #ifdef NEW_LOGGING
2006                 LDAP_LOG( CONFIG, ENTRY, 
2007                         "certificateExactConvert: error parsing cert: %s\n",
2008                         ERR_error_string(ERR_get_error(),NULL), 0, 0 );
2009 #else
2010                 Debug( LDAP_DEBUG_ARGS, "certificateExactConvert: "
2011                         "error parsing cert: %s\n",
2012                         ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
2013 #endif
2014                 return LDAP_INVALID_SYNTAX;
2015         }
2016
2017         if ( !asn1_integer2str(xcert->cert_info->serialNumber, &serial) ) {
2018                 X509_free(xcert);
2019                 return LDAP_INVALID_SYNTAX;
2020         }
2021
2022         rc = dnX509normalize( X509_get_issuer_name(xcert), &issuer_dn );
2023         if( rc != LDAP_SUCCESS ) {
2024                 X509_free(xcert);
2025                 ber_memfree(serial.bv_val);
2026                 return LDAP_INVALID_SYNTAX;
2027         }
2028
2029         X509_free(xcert);
2030
2031         out->bv_len = serial.bv_len + issuer_dn.bv_len + sizeof(" $ ");
2032         out->bv_val = ch_malloc(out->bv_len);
2033         p = out->bv_val;
2034         AC_MEMCPY(p, serial.bv_val, serial.bv_len);
2035         p += serial.bv_len;
2036         AC_MEMCPY(p, " $ ", sizeof(" $ ")-1);
2037         p += 3;
2038         AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
2039         p += issuer_dn.bv_len;
2040         *p++ = '\0';
2041
2042 #ifdef NEW_LOGGING
2043         LDAP_LOG( CONFIG, ARGS, "certificateExactConvert: %s\n",
2044                 out->bv_val, 0, 0 );
2045 #else
2046         Debug( LDAP_DEBUG_ARGS, "certificateExactConvert: %s\n",
2047                 out->bv_val, NULL, NULL );
2048 #endif
2049
2050         ber_memfree(serial.bv_val);
2051         ber_memfree(issuer_dn.bv_val);
2052
2053         return LDAP_SUCCESS;
2054 }
2055
2056 static int
2057 certificateExactNormalize(
2058         slap_mask_t usage,
2059         Syntax *syntax,
2060         MatchingRule *mr,
2061         struct berval *val,
2062         struct berval *normalized,
2063         void *ctx )
2064 {
2065         int rc;
2066
2067         if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage ) ) {
2068                 rc = serialNumberAndIssuerNormalize( usage, syntax, mr,
2069                         val, normalized, ctx );
2070
2071         } else {
2072                 rc = certificateExactConvert( val, normalized );
2073         }
2074
2075         return rc;
2076 }
2077 #endif /* HAVE_TLS */
2078
2079
2080 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
2081 /* slight optimization - does not need the start parameter */
2082 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
2083 enum { start = 0 };
2084 #endif
2085
2086 static int
2087 check_time_syntax (struct berval *val,
2088         int start,
2089         int *parts,
2090         struct berval *fraction)
2091 {
2092         /*
2093          * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
2094          * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
2095          * GeneralizedTime supports leap seconds, UTCTime does not.
2096          */
2097         static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
2098         static const int mdays[2][12] = {
2099                 /* non-leap years */
2100                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
2101                 /* leap years */
2102                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
2103         };
2104         char *p, *e;
2105         int part, c, c1, c2, tzoffset, leapyear = 0;
2106
2107         p = val->bv_val;
2108         e = p + val->bv_len;
2109
2110 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2111         parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
2112 #endif
2113         for (part = start; part < 7 && p < e; part++) {
2114                 c1 = *p;
2115                 if (!ASCII_DIGIT(c1)) {
2116                         break;
2117                 }
2118                 p++;
2119                 if (p == e) {
2120                         return LDAP_INVALID_SYNTAX;
2121                 }
2122                 c = *p++;
2123                 if (!ASCII_DIGIT(c)) {
2124                         return LDAP_INVALID_SYNTAX;
2125                 }
2126                 c += c1 * 10 - '0' * 11;
2127                 if ((part | 1) == 3) {
2128                         --c;
2129                         if (c < 0) {
2130                                 return LDAP_INVALID_SYNTAX;
2131                         }
2132                 }
2133                 if (c >= ceiling[part]) {
2134                         if (! (c == 60 && part == 6 && start == 0))
2135                                 return LDAP_INVALID_SYNTAX;
2136                 }
2137                 parts[part] = c;
2138         }
2139         if (part < 5 + start) {
2140                 return LDAP_INVALID_SYNTAX;
2141         }
2142         for (; part < 9; part++) {
2143                 parts[part] = 0;
2144         }
2145
2146         /* leapyear check for the Gregorian calendar (year>1581) */
2147         if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0)
2148         {
2149                 leapyear = 1;
2150         }
2151
2152         if (parts[3] >= mdays[leapyear][parts[2]]) {
2153                 return LDAP_INVALID_SYNTAX;
2154         }
2155
2156         if (start == 0) {
2157                 fraction->bv_val = p;
2158                 fraction->bv_len = 0;
2159                 if (p < e && (*p == '.' || *p == ',')) {
2160                         char *end_num;
2161                         while (++p < e && ASCII_DIGIT(*p))
2162                                 ;
2163                         if (p - fraction->bv_val == 1) {
2164                                 return LDAP_INVALID_SYNTAX;
2165                         }
2166                         for (end_num = p; end_num[-1] == '0'; --end_num)
2167                                 ;
2168                         c = end_num - fraction->bv_val;
2169                         if (c != 1)
2170                                 fraction->bv_len = c;
2171                 }
2172         }
2173
2174         if (p == e) {
2175                 /* no time zone */
2176                 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2177         }
2178
2179         tzoffset = *p++;
2180         switch (tzoffset) {
2181         default:
2182                 return LDAP_INVALID_SYNTAX;
2183         case 'Z':
2184                 /* UTC */
2185                 break;
2186         case '+':
2187         case '-':
2188                 for (part = 7; part < 9 && p < e; part++) {
2189                         c1 = *p;
2190                         if (!ASCII_DIGIT(c1)) {
2191                                 break;
2192                         }
2193                         p++;
2194                         if (p == e) {
2195                                 return LDAP_INVALID_SYNTAX;
2196                         }
2197                         c2 = *p++;
2198                         if (!ASCII_DIGIT(c2)) {
2199                                 return LDAP_INVALID_SYNTAX;
2200                         }
2201                         parts[part] = c1 * 10 + c2 - '0' * 11;
2202                         if (parts[part] >= ceiling[part]) {
2203                                 return LDAP_INVALID_SYNTAX;
2204                         }
2205                 }
2206                 if (part < 8 + start) {
2207                         return LDAP_INVALID_SYNTAX;
2208                 }
2209
2210                 if (tzoffset == '-') {
2211                         /* negative offset to UTC, ie west of Greenwich */
2212                         parts[4] += parts[7];
2213                         parts[5] += parts[8];
2214                         /* offset is just hhmm, no seconds */
2215                         for (part = 6; --part >= 0; ) {
2216                                 if (part != 3) {
2217                                         c = ceiling[part];
2218                                 } else {
2219                                         c = mdays[leapyear][parts[2]];
2220                                 }
2221                                 if (parts[part] >= c) {
2222                                         if (part == 0) {
2223                                                 return LDAP_INVALID_SYNTAX;
2224                                         }
2225                                         parts[part] -= c;
2226                                         parts[part - 1]++;
2227                                         continue;
2228                                 } else if (part != 5) {
2229                                         break;
2230                                 }
2231                         }
2232                 } else {
2233                         /* positive offset to UTC, ie east of Greenwich */
2234                         parts[4] -= parts[7];
2235                         parts[5] -= parts[8];
2236                         for (part = 6; --part >= 0; ) {
2237                                 if (parts[part] < 0) {
2238                                         if (part == 0) {
2239                                                 return LDAP_INVALID_SYNTAX;
2240                                         }
2241                                         if (part != 3) {
2242                                                 c = ceiling[part];
2243                                         } else {
2244                                                 /* make first arg to % non-negative */
2245                                                 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
2246                                         }
2247                                         parts[part] += c;
2248                                         parts[part - 1]--;
2249                                         continue;
2250                                 } else if (part != 5) {
2251                                         break;
2252                                 }
2253                         }
2254                 }
2255         }
2256
2257         return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2258 }
2259
2260 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2261
2262 #if 0
2263 static int
2264 xutcTimeNormalize(
2265         Syntax *syntax,
2266         struct berval *val,
2267         struct berval *normalized )
2268 {
2269         int parts[9], rc;
2270
2271         rc = check_time_syntax(val, 1, parts, NULL);
2272         if (rc != LDAP_SUCCESS) {
2273                 return rc;
2274         }
2275
2276         normalized->bv_val = ch_malloc( 14 );
2277         if ( normalized->bv_val == NULL ) {
2278                 return LBER_ERROR_MEMORY;
2279         }
2280
2281         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
2282                 parts[1], parts[2] + 1, parts[3] + 1,
2283                 parts[4], parts[5], parts[6] );
2284         normalized->bv_len = 13;
2285
2286         return LDAP_SUCCESS;
2287 }
2288 #endif /* 0 */
2289
2290 static int
2291 utcTimeValidate(
2292         Syntax *syntax,
2293         struct berval *in )
2294 {
2295         int parts[9];
2296         return check_time_syntax(in, 1, parts, NULL);
2297 }
2298
2299 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
2300
2301 static int
2302 generalizedTimeValidate(
2303         Syntax *syntax,
2304         struct berval *in )
2305 {
2306         int parts[9];
2307         struct berval fraction;
2308         return check_time_syntax(in, 0, parts, &fraction);
2309 }
2310
2311 static int
2312 generalizedTimeNormalize(
2313         slap_mask_t usage,
2314         Syntax *syntax,
2315         MatchingRule *mr,
2316         struct berval *val,
2317         struct berval *normalized,
2318         void *ctx )
2319 {
2320         int parts[9], rc;
2321         unsigned int len;
2322         struct berval fraction;
2323
2324         rc = check_time_syntax(val, 0, parts, &fraction);
2325         if (rc != LDAP_SUCCESS) {
2326                 return rc;
2327         }
2328
2329         len = sizeof("YYYYmmddHHMMSSZ")-1 + fraction.bv_len;
2330         normalized->bv_val = sl_malloc( len + 1, ctx );
2331         if ( normalized->bv_val == NULL ) {
2332                 return LBER_ERROR_MEMORY;
2333         }
2334
2335         sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
2336                 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
2337                 parts[4], parts[5], parts[6] );
2338         if ( fraction.bv_len ) {
2339                 memcpy( normalized->bv_val + sizeof("YYYYmmddHHMMSSZ")-2,
2340                         fraction.bv_val, fraction.bv_len );
2341                 normalized->bv_val[sizeof("YYYYmmddHHMMSSZ")-2] = '.';
2342         }
2343         strcpy( normalized->bv_val + len-1, "Z" );
2344         normalized->bv_len = len;
2345
2346         return LDAP_SUCCESS;
2347 }
2348
2349 static int
2350 generalizedTimeOrderingMatch(
2351         int *matchp,
2352         slap_mask_t flags,
2353         Syntax *syntax,
2354         MatchingRule *mr,
2355         struct berval *value,
2356         void *assertedValue )
2357 {
2358         struct berval *asserted = (struct berval *) assertedValue;
2359         ber_len_t v_len  = value->bv_len;
2360         ber_len_t av_len = asserted->bv_len;
2361
2362         /* ignore trailing 'Z' when comparing */
2363         int match = memcmp( value->bv_val, asserted->bv_val,
2364                 (v_len < av_len ? v_len : av_len) - 1 );
2365         if ( match == 0 ) match = v_len - av_len;
2366
2367         *matchp = match;
2368         return LDAP_SUCCESS;
2369 }
2370
2371 static int
2372 nisNetgroupTripleValidate(
2373         Syntax *syntax,
2374         struct berval *val )
2375 {
2376         char *p, *e;
2377         int commas = 0;
2378
2379         if ( val->bv_len == 0 ) {
2380                 return LDAP_INVALID_SYNTAX;
2381         }
2382
2383         p = (char *)val->bv_val;
2384         e = p + val->bv_len;
2385
2386         if ( *p != '(' /*')'*/ ) {
2387                 return LDAP_INVALID_SYNTAX;
2388         }
2389
2390         for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
2391                 if ( *p == ',' ) {
2392                         commas++;
2393                         if ( commas > 2 ) {
2394                                 return LDAP_INVALID_SYNTAX;
2395                         }
2396
2397                 } else if ( !AD_CHAR( *p ) ) {
2398                         return LDAP_INVALID_SYNTAX;
2399                 }
2400         }
2401
2402         if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
2403                 return LDAP_INVALID_SYNTAX;
2404         }
2405
2406         p++;
2407
2408         if (p != e) {
2409                 return LDAP_INVALID_SYNTAX;
2410         }
2411
2412         return LDAP_SUCCESS;
2413 }
2414
2415 static int
2416 bootParameterValidate(
2417         Syntax *syntax,
2418         struct berval *val )
2419 {
2420         char *p, *e;
2421
2422         if ( val->bv_len == 0 ) {
2423                 return LDAP_INVALID_SYNTAX;
2424         }
2425
2426         p = (char *)val->bv_val;
2427         e = p + val->bv_len;
2428
2429         /* key */
2430         for (; ( p < e ) && ( *p != '=' ); p++ ) {
2431                 if ( !AD_CHAR( *p ) ) {
2432                         return LDAP_INVALID_SYNTAX;
2433                 }
2434         }
2435
2436         if ( *p != '=' ) {
2437                 return LDAP_INVALID_SYNTAX;
2438         }
2439
2440         /* server */
2441         for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
2442                 if ( !AD_CHAR( *p ) ) {
2443                         return LDAP_INVALID_SYNTAX;
2444                 }
2445         }
2446
2447         if ( *p != ':' ) {
2448                 return LDAP_INVALID_SYNTAX;
2449         }
2450
2451         /* path */
2452         for ( p++; p < e; p++ ) {
2453                 if ( !SLAP_PRINTABLE( *p ) ) {
2454                         return LDAP_INVALID_SYNTAX;
2455                 }
2456         }
2457
2458         return LDAP_SUCCESS;
2459 }
2460
2461 static int
2462 firstComponentNormalize(
2463         slap_mask_t usage,
2464         Syntax *syntax,
2465         MatchingRule *mr,
2466         struct berval *val,
2467         struct berval *normalized,
2468         void *ctx )
2469 {
2470         int rc;
2471         struct berval oid;
2472         ber_len_t len;
2473
2474         if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2475
2476         if( val->bv_val[0] != '(' /*')'*/ &&
2477                 val->bv_val[0] != '{' /*'}'*/ )
2478         {
2479                 return LDAP_INVALID_SYNTAX;
2480         }
2481
2482         /* trim leading white space */
2483         for( len=1;
2484                 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
2485                 len++ )
2486         {
2487                 /* empty */
2488         }
2489
2490         /* grab next word */
2491         oid.bv_val = &val->bv_val[len];
2492         len = val->bv_len - len;
2493         for( oid.bv_len=0;
2494                 !ASCII_SPACE(oid.bv_val[oid.bv_len]) && oid.bv_len < len;
2495                 oid.bv_len++ )
2496         {
2497                 /* empty */
2498         }
2499
2500         if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
2501                 rc = numericoidValidate( NULL, &oid );
2502         } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
2503                 rc = integerValidate( NULL, &oid );
2504         } else {
2505                 rc = LDAP_INVALID_SYNTAX;
2506         }
2507         
2508
2509         if( rc == LDAP_SUCCESS ) {
2510                 ber_dupbv_x( normalized, &oid, ctx );
2511         }
2512
2513         return rc;
2514 }
2515
2516
2517 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
2518 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
2519
2520 static slap_syntax_defs_rec syntax_defs[] = {
2521         {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
2522                 X_BINARY X_NOT_H_R ")",
2523                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL},
2524         {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
2525                 0, NULL, NULL},
2526         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
2527                 0, NULL, NULL},
2528         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
2529                 X_NOT_H_R ")",
2530                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
2531         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
2532                 X_NOT_H_R ")",
2533                 SLAP_SYNTAX_BER, berValidate, NULL},
2534         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
2535                 0, bitStringValidate, NULL },
2536         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
2537                 0, booleanValidate, NULL},
2538         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
2539                 X_BINARY X_NOT_H_R ")",
2540                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
2541         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
2542                 X_BINARY X_NOT_H_R ")",
2543                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
2544         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
2545                 X_BINARY X_NOT_H_R ")",
2546                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
2547         {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
2548                 0, countryStringValidate, NULL},
2549         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
2550                 0, dnValidate, dnPretty},
2551         {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
2552                 0, NULL, NULL},
2553         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
2554                 0, NULL, NULL},
2555         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
2556                 0, UTF8StringValidate, NULL},
2557         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
2558                 0, NULL, NULL},
2559         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
2560                 0, NULL, NULL},
2561         {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
2562                 0, NULL, NULL},
2563         {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
2564                 0, NULL, NULL},
2565         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
2566                 0, NULL, NULL},
2567         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
2568                 0, printablesStringValidate, NULL},
2569         {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
2570                 SLAP_SYNTAX_BLOB, NULL, NULL},
2571         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
2572                 0, generalizedTimeValidate, NULL},
2573         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
2574                 0, NULL, NULL},
2575         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
2576                 0, IA5StringValidate, NULL},
2577         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
2578                 0, integerValidate, NULL},
2579         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
2580                 SLAP_SYNTAX_BLOB, blobValidate, NULL},
2581         {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
2582                 0, NULL, NULL},
2583         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
2584                 0, NULL, NULL},
2585         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
2586                 0, NULL, NULL},
2587         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
2588                 0, NULL, NULL},
2589         {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
2590                 0, NULL, NULL},
2591         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
2592                 0, nameUIDValidate, nameUIDPretty },
2593         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
2594                 0, NULL, NULL},
2595         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
2596                 0, numericStringValidate, NULL},
2597         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
2598                 0, NULL, NULL},
2599         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
2600                 0, numericoidValidate, NULL},
2601         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
2602                 0, IA5StringValidate, NULL},
2603         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
2604                 0, blobValidate, NULL},
2605         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
2606                 0, UTF8StringValidate, NULL},
2607         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
2608                 0, NULL, NULL},
2609         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
2610                 0, NULL, NULL},
2611         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
2612                 0, printableStringValidate, NULL},
2613         {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
2614 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
2615                 0, subtreeSpecificationValidate, NULL},
2616         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
2617                 X_BINARY X_NOT_H_R ")",
2618                 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
2619         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
2620                 0, printableStringValidate, NULL},
2621         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
2622                 0, NULL, NULL},
2623         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
2624                 0, printablesStringValidate, NULL},
2625 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2626         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
2627                 0, utcTimeValidate, NULL},
2628 #endif
2629         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
2630                 0, NULL, NULL},
2631         {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
2632                 0, NULL, NULL},
2633         {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
2634                 0, NULL, NULL},
2635         {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
2636                 0, NULL, NULL},
2637         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
2638                 0, NULL, NULL},
2639
2640         /* RFC 2307 NIS Syntaxes */
2641         {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
2642                 0, nisNetgroupTripleValidate, NULL},
2643         {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
2644                 0, bootParameterValidate, NULL},
2645
2646         /* From PKIX */
2647         /* These OIDs are not published yet, but will be in the next
2648          * I-D for PKIX LDAPv3 schema as have been advanced by David
2649          * Chadwick in private mail.
2650          */
2651         {"( 1.2.826.0.1.3344810.7.1 DESC 'Serial Number and Issuer' )",
2652                 0, serialNumberAndIssuerValidate, NULL},
2653
2654         /* OpenLDAP Experimental Syntaxes */
2655 #ifdef SLAPD_ACI_ENABLED
2656         {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )",
2657                 SLAP_SYNTAX_HIDE,
2658                 UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */,
2659                 NULL},
2660 #endif
2661
2662 #ifdef SLAPD_AUTHPASSWD
2663         /* needs updating */
2664         {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
2665                 SLAP_SYNTAX_HIDE, NULL, NULL},
2666 #endif
2667
2668         /* OpenLDAP Void Syntax */
2669         {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
2670                 SLAP_SYNTAX_HIDE, inValidate, NULL},
2671         {NULL, 0, NULL, NULL}
2672 };
2673
2674 #ifdef HAVE_TLS
2675 char *certificateExactMatchSyntaxes[] = {
2676         "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
2677         NULL
2678 };
2679 #endif
2680 char *directoryStringSyntaxes[] = {
2681         "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
2682         NULL
2683 };
2684 char *integerFirstComponentMatchSyntaxes[] = {
2685         "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
2686         "1.3.6.1.4.1.1466.115.121.1.17" /* ditStructureRuleDescription */,
2687         NULL
2688 };
2689 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
2690         "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
2691         "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
2692         "1.3.6.1.4.1.1466.115.121.1.16" /* ditContentRuleDescription */,
2693         "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
2694         "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
2695         "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
2696         "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
2697         "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
2698         NULL
2699 };
2700
2701 /*
2702  * Other matching rules in X.520 that we do not use (yet):
2703  *
2704  * 2.5.13.9             numericStringOrderingMatch
2705  * 2.5.13.25    uTCTimeMatch
2706  * 2.5.13.26    uTCTimeOrderingMatch
2707  * 2.5.13.31    directoryStringFirstComponentMatch
2708  * 2.5.13.32    wordMatch
2709  * 2.5.13.33    keywordMatch
2710  * 2.5.13.35    certificateMatch
2711  * 2.5.13.36    certificatePairExactMatch
2712  * 2.5.13.37    certificatePairMatch
2713  * 2.5.13.38    certificateListExactMatch
2714  * 2.5.13.39    certificateListMatch
2715  * 2.5.13.40    algorithmIdentifierMatch
2716  * 2.5.13.41    storedPrefixMatch
2717  * 2.5.13.42    attributeCertificateMatch
2718  * 2.5.13.43    readerAndKeyIDMatch
2719  * 2.5.13.44    attributeIntegrityMatch
2720  */
2721 static slap_mrule_defs_rec mrule_defs[] = {
2722         /*
2723          * EQUALITY matching rules must be listed after associated APPROX
2724          * matching rules.  So, we list all APPROX matching rules first.
2725          */
2726         {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
2727                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2728                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
2729                 NULL, NULL, directoryStringApproxMatch,
2730                 directoryStringApproxIndexer, directoryStringApproxFilter,
2731                 NULL},
2732
2733         {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
2734                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
2735                 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
2736                 NULL, NULL, IA5StringApproxMatch,
2737                 IA5StringApproxIndexer, IA5StringApproxFilter,
2738                 NULL},
2739
2740         /*
2741          * Other matching rules
2742          */
2743         
2744         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
2745                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
2746                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2747                 NULL, NULL, octetStringMatch,
2748                 octetStringIndexer, octetStringFilter,
2749                 NULL },
2750
2751         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
2752                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
2753                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2754                 NULL, dnNormalize, dnMatch,
2755                 octetStringIndexer, octetStringFilter,
2756                 NULL },
2757
2758         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
2759                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2760                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
2761                 NULL, UTF8StringNormalize, octetStringMatch,
2762                 octetStringIndexer, octetStringFilter,
2763                 directoryStringApproxMatchOID },
2764
2765         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
2766                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2767                 SLAP_MR_ORDERING, directoryStringSyntaxes,
2768                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
2769                 NULL, NULL,
2770                 "caseIgnoreMatch" },
2771
2772         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
2773                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2774                 SLAP_MR_SUBSTR, NULL,
2775                 NULL, UTF8StringNormalize, octetStringSubstringsMatch,
2776                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2777                 "caseIgnoreMatch" },
2778
2779         {"( 2.5.13.5 NAME 'caseExactMatch' "
2780                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2781                 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
2782                 NULL, UTF8StringNormalize, octetStringMatch,
2783                 octetStringIndexer, octetStringFilter,
2784                 directoryStringApproxMatchOID },
2785
2786         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
2787                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
2788                 SLAP_MR_ORDERING, directoryStringSyntaxes,
2789                 NULL, UTF8StringNormalize, octetStringOrderingMatch,
2790                 NULL, NULL,
2791                 "caseExactMatch" },
2792
2793         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
2794                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2795                 SLAP_MR_SUBSTR, directoryStringSyntaxes,
2796                 NULL, UTF8StringNormalize, octetStringSubstringsMatch,
2797                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2798                 "caseExactMatch" },
2799
2800         {"( 2.5.13.8 NAME 'numericStringMatch' "
2801                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
2802                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2803                 NULL, numericStringNormalize, octetStringSubstringsMatch,
2804                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2805                 NULL },
2806
2807         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
2808                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2809                 SLAP_MR_SUBSTR, NULL,
2810                 NULL, numericStringNormalize, octetStringSubstringsMatch,
2811                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2812                 "numericStringMatch" },
2813
2814         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
2815                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
2816                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2817                 NULL, NULL, NULL, NULL, NULL, NULL },
2818
2819         {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
2820                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2821                 SLAP_MR_SUBSTR, NULL,
2822                 NULL, NULL, NULL, NULL, NULL,
2823                 "caseIgnoreListMatch" },
2824
2825         {"( 2.5.13.13 NAME 'booleanMatch' "
2826                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
2827                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2828                 NULL, NULL, booleanMatch,
2829                 octetStringIndexer, octetStringFilter,
2830                 NULL },
2831
2832         {"( 2.5.13.14 NAME 'integerMatch' "
2833                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
2834                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2835                 NULL, NULL, integerMatch,
2836                 octetStringIndexer, octetStringFilter,
2837                 NULL },
2838
2839         {"( 2.5.13.15 NAME 'integerOrderingMatch' "
2840                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
2841                 SLAP_MR_ORDERING, NULL,
2842                 NULL, NULL, integerMatch,
2843                 NULL, NULL,
2844                 "integerMatch" },
2845
2846         {"( 2.5.13.16 NAME 'bitStringMatch' "
2847                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
2848                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2849                 NULL, NULL, octetStringMatch,
2850                 octetStringIndexer, octetStringFilter,
2851                 NULL },
2852
2853         {"( 2.5.13.17 NAME 'octetStringMatch' "
2854                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
2855                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2856                 NULL, NULL, octetStringMatch,
2857                 octetStringIndexer, octetStringFilter,
2858                 NULL },
2859
2860         {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
2861                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
2862                 SLAP_MR_ORDERING, NULL,
2863                 NULL, NULL, octetStringOrderingMatch,
2864                 NULL, NULL,
2865                 "octetStringMatch" },
2866
2867         {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
2868                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
2869                 SLAP_MR_SUBSTR, NULL,
2870                 NULL, NULL, octetStringSubstringsMatch,
2871                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2872                 "octetStringMatch" },
2873
2874         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
2875                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
2876                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2877                 NULL,
2878                 telephoneNumberNormalize, octetStringMatch,
2879                 octetStringIndexer, octetStringFilter,
2880                 NULL },
2881
2882         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
2883                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
2884                 SLAP_MR_SUBSTR, NULL,
2885                 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
2886                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2887                 "telephoneNumberMatch" },
2888
2889         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
2890                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
2891                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2892                 NULL, NULL, NULL, NULL, NULL, NULL },
2893
2894         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
2895                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
2896                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2897                 NULL, uniqueMemberNormalize, uniqueMemberMatch,
2898                 NULL, NULL,
2899                 NULL },
2900
2901         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
2902                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
2903                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2904                 NULL, NULL, NULL, NULL, NULL, NULL },
2905
2906         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
2907                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
2908                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2909                 NULL, generalizedTimeNormalize, octetStringMatch,
2910                 NULL, NULL,
2911                 NULL },
2912
2913         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
2914                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
2915                 SLAP_MR_ORDERING, NULL,
2916                 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
2917                 NULL, NULL,
2918                 "generalizedTimeMatch" },
2919
2920         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
2921                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
2922                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
2923                         integerFirstComponentMatchSyntaxes,
2924                 NULL, firstComponentNormalize, integerMatch,
2925                 octetStringIndexer, octetStringFilter,
2926                 NULL },
2927
2928         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
2929                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
2930                 SLAP_MR_EQUALITY | SLAP_MR_EXT,
2931                         objectIdentifierFirstComponentMatchSyntaxes,
2932                 NULL, firstComponentNormalize, octetStringMatch,
2933                 octetStringIndexer, octetStringFilter,
2934                 NULL },
2935
2936 #ifdef HAVE_TLS
2937         {"( 2.5.13.34 NAME 'certificateExactMatch' "
2938                 "SYNTAX 1.2.826.0.1.3344810.7.1 )",
2939                 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
2940                 NULL, certificateExactNormalize, octetStringMatch,
2941                 octetStringIndexer, octetStringFilter,
2942                 NULL },
2943 #endif
2944
2945         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
2946                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
2947                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2948                 NULL, IA5StringNormalize, octetStringMatch,
2949                 octetStringIndexer, octetStringFilter,
2950                 IA5StringApproxMatchOID },
2951
2952         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
2953                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
2954                 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
2955                 NULL, IA5StringNormalize, octetStringMatch,
2956                 octetStringIndexer, octetStringFilter,
2957                 IA5StringApproxMatchOID },
2958
2959         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
2960                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
2961                 SLAP_MR_SUBSTR, NULL,
2962                 NULL, IA5StringNormalize, octetStringSubstringsMatch,
2963                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2964                 "caseIgnoreIA5Match" },
2965
2966         {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
2967                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
2968                 SLAP_MR_SUBSTR, NULL,
2969                 NULL, IA5StringNormalize, octetStringSubstringsMatch,
2970                 octetStringSubstringsIndexer, octetStringSubstringsFilter,
2971                 "caseExactIA5Match" },
2972
2973 #ifdef SLAPD_AUTHPASSWD
2974         /* needs updating */
2975         {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
2976                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
2977                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
2978                 NULL, NULL, authPasswordMatch,
2979                 NULL, NULL,
2980                 NULL},
2981 #endif
2982
2983 #ifdef SLAPD_ACI_ENABLED
2984         {"( 1.3.6.1.4.1.4203.666.4.2 NAME 'OpenLDAPaciMatch' "
2985                 "SYNTAX 1.3.6.1.4.1.4203.666.2.1 )",
2986                 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
2987                 NULL, NULL, OpenLDAPaciMatch,
2988                 NULL, NULL,
2989                 NULL},
2990 #endif
2991
2992         {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
2993                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
2994                 SLAP_MR_EXT, NULL,
2995                 NULL, NULL, integerBitAndMatch,
2996                 NULL, NULL,
2997                 "integerMatch" },
2998
2999         {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
3000                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3001                 SLAP_MR_EXT, NULL,
3002                 NULL, NULL, integerBitOrMatch,
3003                 NULL, NULL,
3004                 "integerMatch" },
3005
3006         {NULL, SLAP_MR_NONE, NULL,
3007                 NULL, NULL, NULL, NULL, NULL,
3008                 NULL }
3009 };
3010
3011 int
3012 slap_schema_init( void )
3013 {
3014         int             res;
3015         int             i;
3016
3017         /* we should only be called once (from main) */
3018         assert( schema_init_done == 0 );
3019
3020         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
3021                 res = register_syntax( &syntax_defs[i] );
3022
3023                 if ( res ) {
3024                         fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
3025                                  syntax_defs[i].sd_desc );
3026                         return LDAP_OTHER;
3027                 }
3028         }
3029
3030         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
3031                 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
3032                         mrule_defs[i].mrd_compat_syntaxes == NULL )
3033                 {
3034                         fprintf( stderr,
3035                                 "slap_schema_init: Ignoring unusable matching rule %s\n",
3036                                  mrule_defs[i].mrd_desc );
3037                         continue;
3038                 }
3039
3040                 res = register_matching_rule( &mrule_defs[i] );
3041
3042                 if ( res ) {
3043                         fprintf( stderr,
3044                                 "slap_schema_init: Error registering matching rule %s\n",
3045                                  mrule_defs[i].mrd_desc );
3046                         return LDAP_OTHER;
3047                 }
3048         }
3049
3050         res = slap_schema_load();
3051         schema_init_done = 1;
3052         return res;
3053 }
3054
3055 void
3056 schema_destroy( void )
3057 {
3058         oidm_destroy();
3059         oc_destroy();
3060         at_destroy();
3061         mr_destroy();
3062         mru_destroy();
3063         syn_destroy();
3064 }