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