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