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