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