1 /* schema_init.c - init builtin schema */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2007 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
26 #include <ac/string.h>
27 #include <ac/socket.h>
30 #include "../../libraries/liblber/lber-int.h" /* get ber_ptrlen() */
32 #include "ldap_utf8.h"
35 #include "lutil_hash.h"
36 #define HASH_BYTES LUTIL_HASH_BYTES
37 #define HASH_CONTEXT lutil_HASH_CTX
38 #define HASH_Init(c) lutil_HASHInit(c)
39 #define HASH_Update(c,buf,len) lutil_HASHUpdate(c,buf,len)
40 #define HASH_Final(d,c) lutil_HASHFinal(d,c)
42 /* approx matching rules */
43 #define directoryStringApproxMatchOID "1.3.6.1.4.1.4203.666.4.4"
44 #define directoryStringApproxMatch approxMatch
45 #define directoryStringApproxIndexer approxIndexer
46 #define directoryStringApproxFilter approxFilter
47 #define IA5StringApproxMatchOID "1.3.6.1.4.1.4203.666.4.5"
48 #define IA5StringApproxMatch approxMatch
49 #define IA5StringApproxIndexer approxIndexer
50 #define IA5StringApproxFilter approxFilter
52 /* Change Sequence Number (CSN) - much of this will change */
53 #define csnValidate blobValidate
54 #define csnMatch octetStringMatch
55 #define csnOrderingMatch octetStringOrderingMatch
56 #define csnIndexer generalizedTimeIndexer
57 #define csnFilter generalizedTimeFilter
59 /* FIXME: temporary */
60 #define authzMatch octetStringMatch
62 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
63 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
64 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
65 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
67 ldap_pvt_thread_mutex_t ad_undef_mutex;
68 ldap_pvt_thread_mutex_t oc_undef_mutex;
75 /* no value allowed */
76 return LDAP_INVALID_SYNTAX;
84 /* any value allowed */
88 #define berValidate blobValidate
95 if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
96 if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
101 /* X.509 related stuff */
109 #define SLAP_X509_OPTION (LBER_CLASS_CONTEXT|LBER_CONSTRUCTED)
112 SLAP_X509_OPT_C_VERSION = SLAP_X509_OPTION + 0,
113 SLAP_X509_OPT_C_ISSUERUNIQUEID = SLAP_X509_OPTION + 1,
114 SLAP_X509_OPT_C_SUBJECTUNIQUEID = SLAP_X509_OPTION + 2,
115 SLAP_X509_OPT_C_EXTENSIONS = SLAP_X509_OPTION + 3
119 SLAP_X509_OPT_CL_CRLEXTENSIONS = SLAP_X509_OPTION + 0
122 /* X.509 certificate validation */
123 static int certificateValidate( Syntax *syntax, struct berval *in )
125 BerElementBuffer berbuf;
126 BerElement *ber = (BerElement *)&berbuf;
129 ber_int_t version = SLAP_X509_V1;
131 ber_init2( ber, in, LBER_USE_DER );
132 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
133 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
134 tag = ber_skip_tag( ber, &len ); /* Sequence */
135 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
136 tag = ber_peek_tag( ber, &len );
137 /* Optional version */
138 if ( tag == SLAP_X509_OPT_C_VERSION ) {
139 tag = ber_skip_tag( ber, &len );
140 tag = ber_get_int( ber, &version );
141 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
143 /* NOTE: don't try to parse Serial, because it might be longer
144 * than sizeof(ber_int_t); deferred to certificateExactNormalize() */
145 tag = ber_skip_tag( ber, &len ); /* Serial */
146 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
147 ber_skip_data( ber, len );
148 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
149 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
150 ber_skip_data( ber, len );
151 tag = ber_skip_tag( ber, &len ); /* Issuer DN */
152 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
153 ber_skip_data( ber, len );
154 tag = ber_skip_tag( ber, &len ); /* Validity */
155 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
156 ber_skip_data( ber, len );
157 tag = ber_skip_tag( ber, &len ); /* Subject DN */
158 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
159 ber_skip_data( ber, len );
160 tag = ber_skip_tag( ber, &len ); /* Subject PublicKeyInfo */
161 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
162 ber_skip_data( ber, len );
163 tag = ber_skip_tag( ber, &len );
164 if ( tag == SLAP_X509_OPT_C_ISSUERUNIQUEID ) { /* issuerUniqueID */
165 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
166 ber_skip_data( ber, len );
167 tag = ber_skip_tag( ber, &len );
169 if ( tag == SLAP_X509_OPT_C_SUBJECTUNIQUEID ) { /* subjectUniqueID */
170 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
171 ber_skip_data( ber, len );
172 tag = ber_skip_tag( ber, &len );
174 if ( tag == SLAP_X509_OPT_C_EXTENSIONS ) { /* Extensions */
175 if ( version < SLAP_X509_V3 ) return LDAP_INVALID_SYNTAX;
176 tag = ber_skip_tag( ber, &len );
177 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
178 ber_skip_data( ber, len );
179 tag = ber_skip_tag( ber, &len );
181 /* signatureAlgorithm */
182 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
183 ber_skip_data( ber, len );
184 tag = ber_skip_tag( ber, &len );
186 if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
187 ber_skip_data( ber, len );
188 tag = ber_skip_tag( ber, &len );
189 /* Must be at end now */
190 if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
194 /* X.509 certificate list validation */
196 static int certificateListValidate( Syntax *syntax, struct berval *in )
198 BerElementBuffer berbuf;
199 BerElement *ber = (BerElement *)&berbuf;
202 ber_int_t version = SLAP_X509_V1;
204 ber_init2( ber, in, LBER_USE_DER );
205 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
206 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
207 tag = ber_skip_tag( ber, &len ); /* Sequence */
208 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
209 tag = ber_peek_tag( ber, &len );
210 /* Optional version */
211 if ( tag == LBER_INTEGER ) {
212 tag = ber_get_int( ber, &version );
213 assert( tag == LBER_INTEGER );
214 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
216 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
217 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
218 ber_skip_data( ber, len );
219 tag = ber_skip_tag( ber, &len ); /* Issuer DN */
220 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
221 ber_skip_data( ber, len );
222 tag = ber_skip_tag( ber, &len ); /* thisUpdate */
223 /* NOTE: in the certificates I'm playing with, the time is UTC.
224 * maybe the tag is different from 0x17U for generalizedTime? */
225 if ( tag != 0x17U ) return LDAP_INVALID_SYNTAX;
226 ber_skip_data( ber, len );
227 /* Optional nextUpdate */
228 tag = ber_skip_tag( ber, &len );
229 if ( tag == 0x17U ) {
230 ber_skip_data( ber, len );
231 tag = ber_skip_tag( ber, &len );
233 /* Optional revokedCertificates */
234 if ( tag == LBER_SEQUENCE ) {
235 /* Should NOT be empty */
236 ber_skip_data( ber, len );
237 tag = ber_skip_tag( ber, &len );
239 /* Optional Extensions */
240 if ( tag == SLAP_X509_OPT_CL_CRLEXTENSIONS ) { /* ? */
241 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
242 tag = ber_skip_tag( ber, &len );
243 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
244 ber_skip_data( ber, len );
245 tag = ber_skip_tag( ber, &len );
247 /* signatureAlgorithm */
248 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
249 ber_skip_data( ber, len );
250 tag = ber_skip_tag( ber, &len );
252 if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
253 ber_skip_data( ber, len );
254 tag = ber_skip_tag( ber, &len );
255 /* Must be at end now */
256 if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
259 #else /* ! LDAP_DEVEL */
260 #define certificateListValidate sequenceValidate
261 #endif /* ! LDAP_DEVEL */
269 struct berval *value,
270 void *assertedValue )
272 struct berval *asserted = (struct berval *) assertedValue;
273 int match = value->bv_len - asserted->bv_len;
276 match = memcmp( value->bv_val, asserted->bv_val, value->bv_len );
284 octetStringOrderingMatch(
289 struct berval *value,
290 void *assertedValue )
292 struct berval *asserted = (struct berval *) assertedValue;
293 ber_len_t v_len = value->bv_len;
294 ber_len_t av_len = asserted->bv_len;
296 int match = memcmp( value->bv_val, asserted->bv_val,
297 (v_len < av_len ? v_len : av_len) );
299 if( match == 0 ) match = v_len - av_len;
307 HASH_CONTEXT *HASHcontext,
308 struct berval *prefix,
313 HASH_Init(HASHcontext);
314 if(prefix && prefix->bv_len > 0) {
315 HASH_Update(HASHcontext,
316 (unsigned char *)prefix->bv_val, prefix->bv_len);
318 if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
319 HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
320 HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
326 HASH_CONTEXT *HASHcontext,
327 unsigned char *HASHdigest,
328 unsigned char *value,
331 HASH_CONTEXT ctx = *HASHcontext;
332 HASH_Update( &ctx, value, len );
333 HASH_Final( HASHdigest, &ctx );
336 /* Index generation function */
337 int octetStringIndexer(
342 struct berval *prefix,
350 HASH_CONTEXT HASHcontext;
351 unsigned char HASHdigest[HASH_BYTES];
352 struct berval digest;
353 digest.bv_val = (char *)HASHdigest;
354 digest.bv_len = sizeof(HASHdigest);
356 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
357 /* just count them */
360 /* we should have at least one value at this point */
363 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
365 slen = syntax->ssyn_oidlen;
366 mlen = mr->smr_oidlen;
368 hashPreset( &HASHcontext, prefix, 0, syntax, mr);
369 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
370 hashIter( &HASHcontext, HASHdigest,
371 (unsigned char *)values[i].bv_val, values[i].bv_len );
372 ber_dupbv_x( &keys[i], &digest, ctx );
375 BER_BVZERO( &keys[i] );
382 /* Index generation function */
383 int octetStringFilter(
388 struct berval *prefix,
389 void * assertedValue,
395 HASH_CONTEXT HASHcontext;
396 unsigned char HASHdigest[HASH_BYTES];
397 struct berval *value = (struct berval *) assertedValue;
398 struct berval digest;
399 digest.bv_val = (char *)HASHdigest;
400 digest.bv_len = sizeof(HASHdigest);
402 slen = syntax->ssyn_oidlen;
403 mlen = mr->smr_oidlen;
405 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
407 hashPreset( &HASHcontext, prefix, 0, syntax, mr );
408 hashIter( &HASHcontext, HASHdigest,
409 (unsigned char *)value->bv_val, value->bv_len );
411 ber_dupbv_x( keys, &digest, ctx );
412 BER_BVZERO( &keys[1] );
420 octetStringSubstringsMatch(
425 struct berval *value,
426 void *assertedValue )
429 SubstringsAssertion *sub = assertedValue;
430 struct berval left = *value;
434 /* Add up asserted input length */
435 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
436 inlen += sub->sa_initial.bv_len;
439 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
440 inlen += sub->sa_any[i].bv_len;
443 if ( !BER_BVISNULL( &sub->sa_final ) ) {
444 inlen += sub->sa_final.bv_len;
447 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
448 if ( inlen > left.bv_len ) {
453 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
454 sub->sa_initial.bv_len );
460 left.bv_val += sub->sa_initial.bv_len;
461 left.bv_len -= sub->sa_initial.bv_len;
462 inlen -= sub->sa_initial.bv_len;
465 if ( !BER_BVISNULL( &sub->sa_final ) ) {
466 if ( inlen > left.bv_len ) {
471 match = memcmp( sub->sa_final.bv_val,
472 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
473 sub->sa_final.bv_len );
479 left.bv_len -= sub->sa_final.bv_len;
480 inlen -= sub->sa_final.bv_len;
484 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
489 if ( inlen > left.bv_len ) {
490 /* not enough length */
495 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
499 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
506 idx = p - left.bv_val;
508 if ( idx >= left.bv_len ) {
509 /* this shouldn't happen */
516 if ( sub->sa_any[i].bv_len > left.bv_len ) {
517 /* not enough left */
522 match = memcmp( left.bv_val,
523 sub->sa_any[i].bv_val,
524 sub->sa_any[i].bv_len );
532 left.bv_val += sub->sa_any[i].bv_len;
533 left.bv_len -= sub->sa_any[i].bv_len;
534 inlen -= sub->sa_any[i].bv_len;
543 /* Substrings Index generation function */
545 octetStringSubstringsIndexer(
550 struct berval *prefix,
559 HASH_CONTEXT HCany, HCini, HCfin;
560 unsigned char HASHdigest[HASH_BYTES];
561 struct berval digest;
562 digest.bv_val = (char *)HASHdigest;
563 digest.bv_len = sizeof(HASHdigest);
567 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
568 /* count number of indices to generate */
569 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
570 if( values[i].bv_len >= index_substr_if_maxlen ) {
571 nkeys += index_substr_if_maxlen -
572 (index_substr_if_minlen - 1);
573 } else if( values[i].bv_len >= index_substr_if_minlen ) {
574 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
578 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
579 if( values[i].bv_len >= index_substr_any_len ) {
580 nkeys += values[i].bv_len - (index_substr_any_len - 1);
584 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
585 if( values[i].bv_len >= index_substr_if_maxlen ) {
586 nkeys += index_substr_if_maxlen -
587 (index_substr_if_minlen - 1);
588 } else if( values[i].bv_len >= index_substr_if_minlen ) {
589 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
595 /* no keys to generate */
600 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
602 slen = syntax->ssyn_oidlen;
603 mlen = mr->smr_oidlen;
605 if ( flags & SLAP_INDEX_SUBSTR_ANY )
606 hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
607 if( flags & SLAP_INDEX_SUBSTR_INITIAL )
608 hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
609 if( flags & SLAP_INDEX_SUBSTR_FINAL )
610 hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
613 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
616 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
617 ( values[i].bv_len >= index_substr_any_len ) )
619 max = values[i].bv_len - (index_substr_any_len - 1);
621 for( j=0; j<max; j++ ) {
622 hashIter( &HCany, HASHdigest,
623 (unsigned char *)&values[i].bv_val[j],
624 index_substr_any_len );
625 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
629 /* skip if too short */
630 if( values[i].bv_len < index_substr_if_minlen ) continue;
632 max = index_substr_if_maxlen < values[i].bv_len
633 ? index_substr_if_maxlen : values[i].bv_len;
635 for( j=index_substr_if_minlen; j<=max; j++ ) {
637 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
638 hashIter( &HCini, HASHdigest,
639 (unsigned char *)values[i].bv_val, j );
640 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
643 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
644 hashIter( &HCfin, HASHdigest,
645 (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
646 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
653 BER_BVZERO( &keys[nkeys] );
664 octetStringSubstringsFilter (
669 struct berval *prefix,
670 void * assertedValue,
674 SubstringsAssertion *sa;
677 size_t slen, mlen, klen;
679 HASH_CONTEXT HASHcontext;
680 unsigned char HASHdigest[HASH_BYTES];
681 struct berval *value;
682 struct berval digest;
684 sa = (SubstringsAssertion *) assertedValue;
686 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
687 !BER_BVISNULL( &sa->sa_initial ) &&
688 sa->sa_initial.bv_len >= index_substr_if_minlen )
691 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
692 ( flags & SLAP_INDEX_SUBSTR_ANY ))
694 nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
698 if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
700 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
701 if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
702 /* don't bother accounting with stepping */
703 nkeys += sa->sa_any[i].bv_len -
704 ( index_substr_any_len - 1 );
709 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
710 !BER_BVISNULL( &sa->sa_final ) &&
711 sa->sa_final.bv_len >= index_substr_if_minlen )
714 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
715 ( flags & SLAP_INDEX_SUBSTR_ANY ))
717 nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
726 digest.bv_val = (char *)HASHdigest;
727 digest.bv_len = sizeof(HASHdigest);
729 slen = syntax->ssyn_oidlen;
730 mlen = mr->smr_oidlen;
732 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
735 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
736 !BER_BVISNULL( &sa->sa_initial ) &&
737 sa->sa_initial.bv_len >= index_substr_if_minlen )
739 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
740 value = &sa->sa_initial;
742 klen = index_substr_if_maxlen < value->bv_len
743 ? index_substr_if_maxlen : value->bv_len;
745 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
746 hashIter( &HASHcontext, HASHdigest,
747 (unsigned char *)value->bv_val, klen );
748 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
750 /* If initial is too long and we have subany indexed, use it
751 * to match the excess...
753 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
756 pre = SLAP_INDEX_SUBSTR_PREFIX;
757 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
758 for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
760 hashIter( &HASHcontext, HASHdigest,
761 (unsigned char *)&value->bv_val[j], index_substr_any_len );
762 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
767 if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
769 pre = SLAP_INDEX_SUBSTR_PREFIX;
770 klen = index_substr_any_len;
772 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
773 if( sa->sa_any[i].bv_len < index_substr_any_len ) {
777 value = &sa->sa_any[i];
779 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
781 j <= value->bv_len - index_substr_any_len;
782 j += index_substr_any_step )
784 hashIter( &HASHcontext, HASHdigest,
785 (unsigned char *)&value->bv_val[j], klen );
786 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
791 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
792 !BER_BVISNULL( &sa->sa_final ) &&
793 sa->sa_final.bv_len >= index_substr_if_minlen )
795 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
796 value = &sa->sa_final;
798 klen = index_substr_if_maxlen < value->bv_len
799 ? index_substr_if_maxlen : value->bv_len;
801 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
802 hashIter( &HASHcontext, HASHdigest,
803 (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
804 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
806 /* If final is too long and we have subany indexed, use it
807 * to match the excess...
809 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
812 pre = SLAP_INDEX_SUBSTR_PREFIX;
813 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
814 for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
816 hashIter( &HASHcontext, HASHdigest,
817 (unsigned char *)&value->bv_val[j], index_substr_any_len );
818 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
824 BER_BVZERO( &keys[nkeys] );
841 /* very unforgiving validation, requires no normalization
842 * before simplistic matching
844 if( in->bv_len < 3 ) {
845 return LDAP_INVALID_SYNTAX;
848 /* RFC 4517 Section 3.3.2 Bit String:
849 * BitString = SQUOTE *binary-digit SQUOTE "B"
850 * binary-digit = "0" / "1"
852 * where SQUOTE [RFC4512] is
853 * SQUOTE = %x27 ; single quote ("'")
855 * Example: '0101111101'B
858 if( in->bv_val[0] != '\'' ||
859 in->bv_val[in->bv_len - 2] != '\'' ||
860 in->bv_val[in->bv_len - 1] != 'B' )
862 return LDAP_INVALID_SYNTAX;
865 for( i = in->bv_len - 3; i > 0; i-- ) {
866 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
867 return LDAP_INVALID_SYNTAX;
875 * Syntaxes from RFC 4517
880 A value of the Bit String syntax is a sequence of binary digits. The
881 LDAP-specific encoding of a value of this syntax is defined by the
884 BitString = SQUOTE *binary-digit SQUOTE "B"
886 binary-digit = "0" / "1"
888 The <SQUOTE> rule is defined in [MODELS].
893 The LDAP definition for the Bit String syntax is:
895 ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
897 This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
901 3.3.21. Name and Optional UID
903 A value of the Name and Optional UID syntax is the distinguished name
904 [MODELS] of an entity optionally accompanied by a unique identifier
905 that serves to differentiate the entity from others with an identical
908 The LDAP-specific encoding of a value of this syntax is defined by
911 NameAndOptionalUID = distinguishedName [ SHARP BitString ]
913 The <BitString> rule is defined in Section 3.3.2. The
914 <distinguishedName> rule is defined in [LDAPDN]. The <SHARP> rule is
917 Note that although the '#' character may occur in the string
918 representation of a distinguished name, no additional escaping of
919 this character is performed when a <distinguishedName> is encoded in
920 a <NameAndOptionalUID>.
923 1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
925 The LDAP definition for the Name and Optional UID syntax is:
927 ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
929 This syntax corresponds to the NameAndOptionalUID ASN.1 type from
936 1.4. Common ABNF Productions
939 SHARP = %x23 ; octothorpe (or sharp sign) ("#")
941 SQUOTE = %x27 ; single quote ("'")
945 * Note: normalization strips any leading "0"s, unless the
946 * bit string is exactly "'0'B", so the normalized example,
947 * in slapd, would result in
949 * 1.3.6.1.4.1.1466.0=#04024869,o=test,c=gb#'101'B
951 * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
952 * be escaped except when at the beginning of a value, the
953 * definition of Name and Optional UID appears to be flawed,
954 * because there is no clear means to determine whether the
955 * UID part is present or not.
959 * cn=Someone,dc=example,dc=com#'1'B
961 * could be either a NameAndOptionalUID with trailing UID, i.e.
963 * DN = "cn=Someone,dc=example,dc=com"
966 * or a NameAndOptionalUID with no trailing UID, and the AVA
967 * in the last RDN made of
970 * attributeValue = com#'1'B
972 * in fact "com#'1'B" is a valid IA5 string.
974 * As a consequence, current slapd code assumes that the
975 * presence of portions of a BitString at the end of the string
976 * representation of a NameAndOptionalUID means a BitString
977 * is expected, and cause an error otherwise. This is quite
978 * arbitrary, and might change in the future.
988 struct berval dn, uid;
990 if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
992 ber_dupbv( &dn, in );
993 if( !dn.bv_val ) return LDAP_OTHER;
995 /* if there's a "#", try bitStringValidate()... */
996 uid.bv_val = strrchr( dn.bv_val, '#' );
997 if ( !BER_BVISNULL( &uid ) ) {
999 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
1001 rc = bitStringValidate( NULL, &uid );
1002 if ( rc == LDAP_SUCCESS ) {
1003 /* in case of success, trim the UID,
1004 * otherwise treat it as part of the DN */
1005 dn.bv_len -= uid.bv_len + 1;
1006 uid.bv_val[-1] = '\0';
1010 rc = dnValidate( NULL, &dn );
1012 ber_memfree( dn.bv_val );
1023 assert( val != NULL );
1024 assert( out != NULL );
1027 Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
1029 if( BER_BVISEMPTY( val ) ) {
1030 ber_dupbv_x( out, val, ctx );
1032 } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
1033 return LDAP_INVALID_SYNTAX;
1037 struct berval dnval = *val;
1038 struct berval uidval = BER_BVNULL;
1040 uidval.bv_val = strrchr( val->bv_val, '#' );
1041 if ( !BER_BVISNULL( &uidval ) ) {
1043 uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
1045 rc = bitStringValidate( NULL, &uidval );
1047 if ( rc == LDAP_SUCCESS ) {
1048 ber_dupbv_x( &dnval, val, ctx );
1049 dnval.bv_len -= uidval.bv_len + 1;
1050 dnval.bv_val[dnval.bv_len] = '\0';
1053 BER_BVZERO( &uidval );
1057 rc = dnPretty( syntax, &dnval, out, ctx );
1058 if ( dnval.bv_val != val->bv_val ) {
1059 slap_sl_free( dnval.bv_val, ctx );
1061 if( rc != LDAP_SUCCESS ) {
1065 if( !BER_BVISNULL( &uidval ) ) {
1069 tmp = slap_sl_realloc( out->bv_val, out->bv_len
1070 + STRLENOF( "#" ) + uidval.bv_len + 1,
1073 ber_memfree_x( out->bv_val, ctx );
1077 out->bv_val[out->bv_len++] = '#';
1078 out->bv_val[out->bv_len++] = '\'';
1080 got1 = uidval.bv_len < sizeof("'0'B");
1081 for( i = 1; i < uidval.bv_len - 2; i++ ) {
1082 c = uidval.bv_val[i];
1085 if( got1 ) out->bv_val[out->bv_len++] = c;
1089 out->bv_val[out->bv_len++] = c;
1094 out->bv_val[out->bv_len++] = '\'';
1095 out->bv_val[out->bv_len++] = 'B';
1096 out->bv_val[out->bv_len] = '\0';
1100 Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1102 return LDAP_SUCCESS;
1106 uniqueMemberNormalize(
1111 struct berval *normalized,
1117 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1119 ber_dupbv_x( &out, val, ctx );
1120 if ( BER_BVISEMPTY( &out ) ) {
1124 struct berval uid = BER_BVNULL;
1126 uid.bv_val = strrchr( out.bv_val, '#' );
1127 if ( !BER_BVISNULL( &uid ) ) {
1129 uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1131 rc = bitStringValidate( NULL, &uid );
1132 if ( rc == LDAP_SUCCESS ) {
1133 uid.bv_val[-1] = '\0';
1134 out.bv_len -= uid.bv_len + 1;
1140 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1142 if( rc != LDAP_SUCCESS ) {
1143 slap_sl_free( out.bv_val, ctx );
1144 return LDAP_INVALID_SYNTAX;
1147 if( !BER_BVISNULL( &uid ) ) {
1150 tmp = ch_realloc( normalized->bv_val,
1151 normalized->bv_len + uid.bv_len
1152 + STRLENOF("#") + 1 );
1153 if ( tmp == NULL ) {
1154 ber_memfree_x( normalized->bv_val, ctx );
1158 normalized->bv_val = tmp;
1160 /* insert the separator */
1161 normalized->bv_val[normalized->bv_len++] = '#';
1163 /* append the UID */
1164 AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1165 uid.bv_val, uid.bv_len );
1166 normalized->bv_len += uid.bv_len;
1169 normalized->bv_val[normalized->bv_len] = '\0';
1172 slap_sl_free( out.bv_val, ctx );
1175 return LDAP_SUCCESS;
1184 struct berval *value,
1185 void *assertedValue )
1188 struct berval *asserted = (struct berval *) assertedValue;
1189 struct berval assertedDN = *asserted;
1190 struct berval assertedUID = BER_BVNULL;
1191 struct berval valueDN = *value;
1192 struct berval valueUID = BER_BVNULL;
1193 int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1195 if ( !BER_BVISEMPTY( asserted ) ) {
1196 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1197 if ( !BER_BVISNULL( &assertedUID ) ) {
1198 assertedUID.bv_val++;
1199 assertedUID.bv_len = assertedDN.bv_len
1200 - ( assertedUID.bv_val - assertedDN.bv_val );
1202 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1203 assertedDN.bv_len -= assertedUID.bv_len + 1;
1206 BER_BVZERO( &assertedUID );
1211 if ( !BER_BVISEMPTY( value ) ) {
1213 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1214 if ( !BER_BVISNULL( &valueUID ) ) {
1216 valueUID.bv_len = valueDN.bv_len
1217 - ( valueUID.bv_val - valueDN.bv_val );
1219 if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1220 valueDN.bv_len -= valueUID.bv_len + 1;
1223 BER_BVZERO( &valueUID );
1228 if( valueUID.bv_len && assertedUID.bv_len ) {
1229 match = valueUID.bv_len - assertedUID.bv_len;
1232 return LDAP_SUCCESS;
1235 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1238 return LDAP_SUCCESS;
1241 } else if ( !approx && valueUID.bv_len ) {
1244 return LDAP_SUCCESS;
1246 } else if ( !approx && assertedUID.bv_len ) {
1249 return LDAP_SUCCESS;
1252 return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1256 uniqueMemberIndexer(
1261 struct berval *prefix,
1269 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1270 /* just count them */
1274 dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1276 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1277 struct berval assertedDN = values[i];
1278 struct berval assertedUID = BER_BVNULL;
1280 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1281 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1282 if ( !BER_BVISNULL( &assertedUID ) ) {
1283 assertedUID.bv_val++;
1284 assertedUID.bv_len = assertedDN.bv_len
1285 - ( assertedUID.bv_val - assertedDN.bv_val );
1287 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1288 assertedDN.bv_len -= assertedUID.bv_len + 1;
1291 BER_BVZERO( &assertedUID );
1296 dnvalues[i] = assertedDN;
1298 BER_BVZERO( &dnvalues[i] );
1300 rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1301 dnvalues, keysp, ctx );
1303 slap_sl_free( dnvalues, ctx );
1313 struct berval *prefix,
1314 void * assertedValue,
1318 struct berval *asserted = (struct berval *) assertedValue;
1319 struct berval assertedDN = *asserted;
1320 struct berval assertedUID = BER_BVNULL;
1322 if ( !BER_BVISEMPTY( asserted ) ) {
1323 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1324 if ( !BER_BVISNULL( &assertedUID ) ) {
1325 assertedUID.bv_val++;
1326 assertedUID.bv_len = assertedDN.bv_len
1327 - ( assertedUID.bv_val - assertedDN.bv_val );
1329 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1330 assertedDN.bv_len -= assertedUID.bv_len + 1;
1333 BER_BVZERO( &assertedUID );
1338 return octetStringFilter( use, flags, syntax, mr, prefix,
1339 &assertedDN, keysp, ctx );
1344 * Handling boolean syntax and matching is quite rigid.
1345 * A more flexible approach would be to allow a variety
1346 * of strings to be normalized and prettied into TRUE
1354 /* very unforgiving validation, requires no normalization
1355 * before simplistic matching
1358 if( in->bv_len == 4 ) {
1359 if( bvmatch( in, &slap_true_bv ) ) {
1360 return LDAP_SUCCESS;
1362 } else if( in->bv_len == 5 ) {
1363 if( bvmatch( in, &slap_false_bv ) ) {
1364 return LDAP_SUCCESS;
1368 return LDAP_INVALID_SYNTAX;
1377 struct berval *value,
1378 void *assertedValue )
1380 /* simplistic matching allowed by rigid validation */
1381 struct berval *asserted = (struct berval *) assertedValue;
1382 *matchp = value->bv_len != asserted->bv_len;
1383 return LDAP_SUCCESS;
1386 /*-------------------------------------------------------------------
1387 LDAP/X.500 string syntax / matching rules have a few oddities. This
1388 comment attempts to detail how slapd(8) treats them.
1391 StringSyntax X.500 LDAP Matching/Comments
1392 DirectoryString CHOICE UTF8 i/e + ignore insignificant spaces
1393 PrintableString subset subset i/e + ignore insignificant spaces
1394 PrintableString subset subset i/e + ignore insignificant spaces
1395 NumericString subset subset ignore all spaces
1396 IA5String ASCII ASCII i/e + ignore insignificant spaces
1397 TeletexString T.61 T.61 i/e + ignore insignificant spaces
1399 TelephoneNumber subset subset i + ignore all spaces and "-"
1401 See RFC 4518 for details.
1405 In X.500(93), a directory string can be either a PrintableString,
1406 a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1407 In later versions, more CHOICEs were added. In all cases the string
1410 In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1411 A directory string cannot be zero length.
1413 For matching, there are both case ignore and exact rules. Both
1414 also require that "insignificant" spaces be ignored.
1415 spaces before the first non-space are ignored;
1416 spaces after the last non-space are ignored;
1417 spaces after a space are ignored.
1418 Note: by these rules (and as clarified in X.520), a string of only
1419 spaces is to be treated as if held one space, not empty (which
1420 would be a syntax error).
1423 In ASN.1, numeric string is just a string of digits and spaces
1424 and could be empty. However, in X.500, all attribute values of
1425 numeric string carry a non-empty constraint. For example:
1427 internationalISDNNumber ATTRIBUTE ::= {
1428 WITH SYNTAX InternationalISDNNumber
1429 EQUALITY MATCHING RULE numericStringMatch
1430 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1431 ID id-at-internationalISDNNumber }
1432 InternationalISDNNumber ::=
1433 NumericString (SIZE(1..ub-international-isdn-number))
1435 Unforunately, some assertion values are don't carry the same
1436 constraint (but its unclear how such an assertion could ever
1437 be true). In LDAP, there is one syntax (numericString) not two
1438 (numericString with constraint, numericString without constraint).
1439 This should be treated as numericString with non-empty constraint.
1440 Note that while someone may have no ISDN number, there are no ISDN
1441 numbers which are zero length.
1443 In matching, spaces are ignored.
1446 In ASN.1, Printable string is just a string of printable characters
1447 and can be empty. In X.500, semantics much like NumericString (see
1448 serialNumber for a like example) excepting uses insignificant space
1449 handling instead of ignore all spaces.
1452 Basically same as PrintableString. There are no examples in X.500,
1453 but same logic applies. So we require them to be non-empty as
1456 -------------------------------------------------------------------*/
1465 unsigned char *u = (unsigned char *)in->bv_val;
1467 if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1468 /* directory strings cannot be empty */
1469 return LDAP_INVALID_SYNTAX;
1472 for( count = in->bv_len; count > 0; count -= len, u += len ) {
1473 /* get the length indicated by the first byte */
1474 len = LDAP_UTF8_CHARLEN2( u, len );
1476 /* very basic checks */
1479 if( (u[5] & 0xC0) != 0x80 ) {
1480 return LDAP_INVALID_SYNTAX;
1483 if( (u[4] & 0xC0) != 0x80 ) {
1484 return LDAP_INVALID_SYNTAX;
1487 if( (u[3] & 0xC0) != 0x80 ) {
1488 return LDAP_INVALID_SYNTAX;
1491 if( (u[2] & 0xC0 )!= 0x80 ) {
1492 return LDAP_INVALID_SYNTAX;
1495 if( (u[1] & 0xC0) != 0x80 ) {
1496 return LDAP_INVALID_SYNTAX;
1499 /* CHARLEN already validated it */
1502 return LDAP_INVALID_SYNTAX;
1505 /* make sure len corresponds with the offset
1506 to the next character */
1507 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1511 return LDAP_INVALID_SYNTAX;
1514 return LDAP_SUCCESS;
1518 UTF8StringNormalize(
1523 struct berval *normalized,
1526 struct berval tmp, nvalue;
1530 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
1532 if( BER_BVISNULL( val ) ) {
1533 /* assume we're dealing with a syntax (e.g., UTF8String)
1534 * which allows empty strings
1536 BER_BVZERO( normalized );
1537 return LDAP_SUCCESS;
1540 flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1541 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1542 flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1543 ? LDAP_UTF8_APPROX : 0;
1545 val = UTF8bvnormalize( val, &tmp, flags, ctx );
1550 /* collapse spaces (in place) */
1552 nvalue.bv_val = tmp.bv_val;
1554 /* trim leading spaces? */
1555 wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1556 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1558 for( i = 0; i < tmp.bv_len; i++) {
1559 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1560 if( wasspace++ == 0 ) {
1561 /* trim repeated spaces */
1562 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1566 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1570 if( !BER_BVISEMPTY( &nvalue ) ) {
1571 /* trim trailing space? */
1573 (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1574 ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1578 nvalue.bv_val[nvalue.bv_len] = '\0';
1581 /* string of all spaces is treated as one space */
1582 nvalue.bv_val[0] = ' ';
1583 nvalue.bv_val[1] = '\0';
1587 *normalized = nvalue;
1588 return LDAP_SUCCESS;
1592 directoryStringSubstringsMatch(
1597 struct berval *value,
1598 void *assertedValue )
1601 SubstringsAssertion *sub = assertedValue;
1602 struct berval left = *value;
1606 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1607 if ( sub->sa_initial.bv_len > left.bv_len ) {
1608 /* not enough left */
1613 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1614 sub->sa_initial.bv_len );
1620 left.bv_val += sub->sa_initial.bv_len;
1621 left.bv_len -= sub->sa_initial.bv_len;
1623 priorspace = ASCII_SPACE(
1624 sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1627 if ( sub->sa_any ) {
1628 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1632 if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] )
1633 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1635 /* allow next space to match */
1642 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1646 if ( sub->sa_any[i].bv_len > left.bv_len ) {
1647 /* not enough left */
1652 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1659 idx = p - left.bv_val;
1661 if ( idx >= left.bv_len ) {
1662 /* this shouldn't happen */
1669 if ( sub->sa_any[i].bv_len > left.bv_len ) {
1670 /* not enough left */
1675 match = memcmp( left.bv_val,
1676 sub->sa_any[i].bv_val,
1677 sub->sa_any[i].bv_len );
1685 left.bv_val += sub->sa_any[i].bv_len;
1686 left.bv_len -= sub->sa_any[i].bv_len;
1688 priorspace = ASCII_SPACE(
1689 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1693 if ( !BER_BVISNULL( &sub->sa_final ) ) {
1694 if( priorspace && !BER_BVISEMPTY( &sub->sa_final )
1695 && ASCII_SPACE( sub->sa_final.bv_val[0] ))
1697 /* allow next space to match */
1702 if ( sub->sa_final.bv_len > left.bv_len ) {
1703 /* not enough left */
1708 match = memcmp( sub->sa_final.bv_val,
1709 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1710 sub->sa_final.bv_len );
1719 return LDAP_SUCCESS;
1722 #if defined(SLAPD_APPROX_INITIALS)
1723 # define SLAPD_APPROX_DELIMITER "._ "
1724 # define SLAPD_APPROX_WORDLEN 2
1726 # define SLAPD_APPROX_DELIMITER " "
1727 # define SLAPD_APPROX_WORDLEN 1
1736 struct berval *value,
1737 void *assertedValue )
1739 struct berval *nval, *assertv;
1740 char *val, **values, **words, *c;
1741 int i, count, len, nextchunk=0, nextavail=0;
1743 /* Yes, this is necessary */
1744 nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
1745 if( nval == NULL ) {
1747 return LDAP_SUCCESS;
1750 /* Yes, this is necessary */
1751 assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1752 NULL, LDAP_UTF8_APPROX, NULL );
1753 if( assertv == NULL ) {
1756 return LDAP_SUCCESS;
1759 /* Isolate how many words there are */
1760 for ( c = nval->bv_val, count = 1; *c; c++ ) {
1761 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1762 if ( c == NULL ) break;
1767 /* Get a phonetic copy of each word */
1768 words = (char **)ch_malloc( count * sizeof(char *) );
1769 values = (char **)ch_malloc( count * sizeof(char *) );
1770 for ( c = nval->bv_val, i = 0; i < count; i++, c += strlen(c) + 1 ) {
1772 values[i] = phonetic(c);
1775 /* Work through the asserted value's words, to see if at least some
1776 of the words are there, in the same order. */
1778 while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1779 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1784 #if defined(SLAPD_APPROX_INITIALS)
1785 else if( len == 1 ) {
1786 /* Single letter words need to at least match one word's initial */
1787 for( i=nextavail; i<count; i++ )
1788 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1795 /* Isolate the next word in the asserted value and phonetic it */
1796 assertv->bv_val[nextchunk+len] = '\0';
1797 val = phonetic( assertv->bv_val + nextchunk );
1799 /* See if this phonetic chunk is in the remaining words of *value */
1800 for( i=nextavail; i<count; i++ ){
1801 if( !strcmp( val, values[i] ) ){
1809 /* This chunk in the asserted value was NOT within the *value. */
1815 /* Go on to the next word in the asserted value */
1819 /* If some of the words were seen, call it a match */
1820 if( nextavail > 0 ) {
1827 /* Cleanup allocs */
1828 ber_bvfree( assertv );
1829 for( i=0; i<count; i++ ) {
1830 ch_free( values[i] );
1836 return LDAP_SUCCESS;
1845 struct berval *prefix,
1851 int i,j, len, wordcount, keycount=0;
1852 struct berval *newkeys;
1853 BerVarray keys=NULL;
1855 for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
1856 struct berval val = BER_BVNULL;
1857 /* Yes, this is necessary */
1858 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
1859 assert( !BER_BVISNULL( &val ) );
1861 /* Isolate how many words there are. There will be a key for each */
1862 for( wordcount = 0, c = val.bv_val; *c; c++) {
1863 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1864 if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1866 if (*c == '\0') break;
1870 /* Allocate/increase storage to account for new keys */
1871 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1)
1872 * sizeof(struct berval) );
1873 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1874 if( keys ) ch_free( keys );
1877 /* Get a phonetic copy of each word */
1878 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1880 if( len < SLAPD_APPROX_WORDLEN ) continue;
1881 ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1886 ber_memfree( val.bv_val );
1888 BER_BVZERO( &keys[keycount] );
1891 return LDAP_SUCCESS;
1900 struct berval *prefix,
1901 void * assertedValue,
1910 /* Yes, this is necessary */
1911 val = UTF8bvnormalize( ((struct berval *)assertedValue),
1912 NULL, LDAP_UTF8_APPROX, NULL );
1913 if( val == NULL || BER_BVISNULL( val ) ) {
1914 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1915 BER_BVZERO( &keys[0] );
1918 return LDAP_SUCCESS;
1921 /* Isolate how many words there are. There will be a key for each */
1922 for( count = 0,c = val->bv_val; *c; c++) {
1923 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1924 if( len >= SLAPD_APPROX_WORDLEN ) count++;
1926 if (*c == '\0') break;
1930 /* Allocate storage for new keys */
1931 keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1933 /* Get a phonetic copy of each word */
1934 for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1936 if( len < SLAPD_APPROX_WORDLEN ) continue;
1937 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1943 BER_BVZERO( &keys[count] );
1946 return LDAP_SUCCESS;
1949 /* Remove all spaces and '-' characters */
1951 telephoneNumberNormalize(
1956 struct berval *normalized,
1961 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1963 /* validator should have refused an empty string */
1964 assert( !BER_BVISEMPTY( val ) );
1966 q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
1968 for( p = val->bv_val; *p; p++ ) {
1969 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1975 normalized->bv_len = q - normalized->bv_val;
1977 if( BER_BVISEMPTY( normalized ) ) {
1978 slap_sl_free( normalized->bv_val, ctx );
1979 BER_BVZERO( normalized );
1980 return LDAP_INVALID_SYNTAX;
1983 return LDAP_SUCCESS;
1991 struct berval val = *in;
1993 if( BER_BVISEMPTY( &val ) ) {
1994 /* disallow empty strings */
1995 return LDAP_INVALID_SYNTAX;
1998 while( OID_LEADCHAR( val.bv_val[0] ) ) {
1999 if ( val.bv_len == 1 ) {
2000 return LDAP_SUCCESS;
2003 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2010 while ( OID_LEADCHAR( val.bv_val[0] )) {
2014 if ( val.bv_len == 0 ) {
2015 return LDAP_SUCCESS;
2019 if( !OID_SEPARATOR( val.bv_val[0] )) {
2027 return LDAP_INVALID_SYNTAX;
2036 struct berval val = *in;
2038 if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2040 if ( val.bv_val[0] == '-' ) {
2044 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2045 return LDAP_INVALID_SYNTAX;
2048 if( val.bv_val[0] == '0' ) { /* "-0" */
2049 return LDAP_INVALID_SYNTAX;
2052 } else if ( val.bv_val[0] == '0' ) {
2053 if( val.bv_len > 1 ) { /* "0<more>" */
2054 return LDAP_INVALID_SYNTAX;
2057 return LDAP_SUCCESS;
2060 for( i=0; i < val.bv_len; i++ ) {
2061 if( !ASCII_DIGIT(val.bv_val[i]) ) {
2062 return LDAP_INVALID_SYNTAX;
2066 return LDAP_SUCCESS;
2075 struct berval *value,
2076 void *assertedValue )
2078 struct berval *asserted = (struct berval *) assertedValue;
2079 int vsign = 1, asign = 1; /* default sign = '+' */
2084 if( v.bv_val[0] == '-' ) {
2090 if( BER_BVISEMPTY( &v ) ) vsign = 0;
2093 if( a.bv_val[0] == '-' ) {
2099 if( BER_BVISEMPTY( &a ) ) vsign = 0;
2101 match = vsign - asign;
2103 match = ( v.bv_len != a.bv_len
2104 ? ( v.bv_len < a.bv_len ? -1 : 1 )
2105 : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2106 if( vsign < 0 ) match = -match;
2110 return LDAP_SUCCESS;
2114 countryStringValidate(
2116 struct berval *val )
2118 if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2120 if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2121 return LDAP_INVALID_SYNTAX;
2123 if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2124 return LDAP_INVALID_SYNTAX;
2127 return LDAP_SUCCESS;
2131 printableStringValidate(
2133 struct berval *val )
2137 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2139 for(i=0; i < val->bv_len; i++) {
2140 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2141 return LDAP_INVALID_SYNTAX;
2145 return LDAP_SUCCESS;
2149 printablesStringValidate(
2151 struct berval *val )
2155 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2157 for(i=0,len=0; i < val->bv_len; i++) {
2158 int c = val->bv_val[i];
2162 return LDAP_INVALID_SYNTAX;
2166 } else if ( SLAP_PRINTABLE(c) ) {
2169 return LDAP_INVALID_SYNTAX;
2174 return LDAP_INVALID_SYNTAX;
2177 return LDAP_SUCCESS;
2183 struct berval *val )
2187 for(i=0; i < val->bv_len; i++) {
2188 if( !LDAP_ASCII(val->bv_val[i]) ) {
2189 return LDAP_INVALID_SYNTAX;
2193 return LDAP_SUCCESS;
2202 struct berval *normalized,
2206 int casefold = !SLAP_MR_ASSOCIATED( mr,
2207 slap_schema.si_mr_caseExactIA5Match );
2209 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2213 /* Ignore initial whitespace */
2214 while ( ASCII_SPACE( *p ) ) p++;
2216 normalized->bv_len = val->bv_len - ( p - val->bv_val );
2217 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2218 AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2219 normalized->bv_val[normalized->bv_len] = '\0';
2221 p = q = normalized->bv_val;
2224 if ( ASCII_SPACE( *p ) ) {
2227 /* Ignore the extra whitespace */
2228 while ( ASCII_SPACE( *p ) ) {
2232 } else if ( casefold ) {
2233 /* Most IA5 rules require casefolding */
2234 *q++ = TOLOWER(*p); p++;
2241 assert( normalized->bv_val <= p );
2245 * If the string ended in space, backup the pointer one
2246 * position. One is enough because the above loop collapsed
2247 * all whitespace to a single space.
2249 if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2251 /* null terminate */
2254 normalized->bv_len = q - normalized->bv_val;
2256 return LDAP_SUCCESS;
2265 if( in->bv_len != 36 ) {
2266 return LDAP_INVALID_SYNTAX;
2269 for( i=0; i<36; i++ ) {
2275 if( in->bv_val[i] != '-' ) {
2276 return LDAP_INVALID_SYNTAX;
2280 if( !ASCII_HEX( in->bv_val[i]) ) {
2281 return LDAP_INVALID_SYNTAX;
2286 return LDAP_SUCCESS;
2297 int rc=LDAP_INVALID_SYNTAX;
2299 assert( in != NULL );
2300 assert( out != NULL );
2302 if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2305 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2307 for( i=0; i<36; i++ ) {
2313 if( in->bv_val[i] != '-' ) {
2316 out->bv_val[i] = '-';
2320 if( !ASCII_HEX( in->bv_val[i]) ) {
2323 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2328 out->bv_val[ out->bv_len ] = '\0';
2332 slap_sl_free( out->bv_val, ctx );
2345 struct berval *normalized,
2348 unsigned char octet = '\0';
2351 normalized->bv_len = 16;
2352 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2354 for( i=0, j=0; i<36; i++ ) {
2355 unsigned char nibble;
2356 if( val->bv_val[i] == '-' ) {
2359 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2360 nibble = val->bv_val[i] - '0';
2362 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2363 nibble = val->bv_val[i] - ('a'-10);
2365 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2366 nibble = val->bv_val[i] - ('A'-10);
2369 slap_sl_free( normalized->bv_val, ctx );
2370 return LDAP_INVALID_SYNTAX;
2375 normalized->bv_val[j>>1] = octet;
2377 octet = nibble << 4;
2382 normalized->bv_val[normalized->bv_len] = 0;
2383 return LDAP_SUCCESS;
2389 numericStringValidate(
2395 if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2397 for(i=0; i < in->bv_len; i++) {
2398 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2399 return LDAP_INVALID_SYNTAX;
2403 return LDAP_SUCCESS;
2407 numericStringNormalize(
2412 struct berval *normalized,
2415 /* removal all spaces */
2418 assert( !BER_BVISEMPTY( val ) );
2420 normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2423 q = normalized->bv_val;
2426 if ( ASCII_SPACE( *p ) ) {
2427 /* Ignore whitespace */
2434 /* we should have copied no more then is in val */
2435 assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2437 /* null terminate */
2440 normalized->bv_len = q - normalized->bv_val;
2442 if( BER_BVISEMPTY( normalized ) ) {
2443 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2444 normalized->bv_val[0] = ' ';
2445 normalized->bv_val[1] = '\0';
2446 normalized->bv_len = 1;
2449 return LDAP_SUCCESS;
2453 * Integer conversion macros that will use the largest available
2456 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
2457 # define SLAP_STRTOL(n,e,b) strtoll(n,e,b)
2458 # define SLAP_LONG long long
2460 # define SLAP_STRTOL(n,e,b) strtol(n,e,b)
2461 # define SLAP_LONG long
2462 #endif /* HAVE_STRTOLL ... */
2470 struct berval *value,
2471 void *assertedValue )
2473 SLAP_LONG lValue, lAssertedValue;
2476 /* safe to assume integers are NUL terminated? */
2477 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2478 if( errno == ERANGE )
2480 return LDAP_CONSTRAINT_VIOLATION;
2483 lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2485 if( errno == ERANGE )
2487 return LDAP_CONSTRAINT_VIOLATION;
2490 *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2491 return LDAP_SUCCESS;
2500 struct berval *value,
2501 void *assertedValue )
2503 SLAP_LONG lValue, lAssertedValue;
2506 /* safe to assume integers are NUL terminated? */
2507 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2508 if( errno == ERANGE )
2510 return LDAP_CONSTRAINT_VIOLATION;
2513 lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2515 if( errno == ERANGE )
2517 return LDAP_CONSTRAINT_VIOLATION;
2520 *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2521 return LDAP_SUCCESS;
2525 serialNumberAndIssuerValidate(
2531 struct berval sn, i;
2533 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
2536 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2538 if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2539 /* Parse old format */
2540 i.bv_val = ber_bvchr( in, '$' );
2541 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2543 sn.bv_val = in->bv_val;
2544 sn.bv_len = i.bv_val - in->bv_val;
2547 i.bv_len = in->bv_len - (sn.bv_len + 1);
2549 /* eat leading zeros */
2550 for( n=0; n < (sn.bv_len-1); n++ ) {
2551 if( sn.bv_val[n] != '0' ) break;
2556 for( n=0; n < sn.bv_len; n++ ) {
2557 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2561 /* Parse GSER format */
2562 int havesn=0,haveissuer=0;
2563 struct berval x = *in;
2567 /* eat leading spaces */
2568 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2572 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2573 return LDAP_INVALID_SYNTAX;
2576 /* should be at issuer or serialNumber NamedValue */
2577 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2579 x.bv_val += STRLENOF("issuer");
2580 x.bv_len -= STRLENOF("issuer");
2582 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2583 x.bv_val++; x.bv_len--;
2585 /* eat leading spaces */
2586 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2590 if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2591 x.bv_val++; x.bv_len--;
2593 i.bv_val = x.bv_val;
2596 for( ; i.bv_len < x.bv_len; ) {
2597 if ( i.bv_val[i.bv_len] != '"' ) {
2601 if ( i.bv_val[i.bv_len+1] == '"' ) {
2608 x.bv_val += i.bv_len+1;
2609 x.bv_len -= i.bv_len+1;
2611 if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2612 return LDAP_INVALID_SYNTAX;
2617 } else if( strncasecmp( x.bv_val, "serialNumber",
2618 STRLENOF("serialNumber")) == 0 )
2620 /* parse serialNumber */
2622 x.bv_val += STRLENOF("serialNumber");
2623 x.bv_len -= STRLENOF("serialNumber");
2625 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2626 x.bv_val++; x.bv_len--;
2628 /* eat leading spaces */
2629 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2633 sn.bv_val = x.bv_val;
2636 if( sn.bv_val[0] == '-' ) {
2641 for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2642 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2645 if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2646 if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2647 return LDAP_INVALID_SYNTAX;
2650 x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
2652 if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2653 return LDAP_INVALID_SYNTAX;
2658 } else return LDAP_INVALID_SYNTAX;
2660 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2661 x.bv_val++; x.bv_len--;
2664 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2668 /* should be at remaining NamedValue */
2669 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2670 STRLENOF("issuer" )) == 0 ))
2673 x.bv_val += STRLENOF("issuer");
2674 x.bv_len -= STRLENOF("issuer");
2676 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2677 x.bv_val++; x.bv_len--;
2679 /* eat leading spaces */
2680 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2684 if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2685 x.bv_val++; x.bv_len--;
2687 i.bv_val = x.bv_val;
2690 for( ; i.bv_len < x.bv_len; ) {
2691 if ( i.bv_val[i.bv_len] != '"' ) {
2695 if ( i.bv_val[i.bv_len+1] == '"' ) {
2702 x.bv_val += i.bv_len+1;
2703 x.bv_len -= i.bv_len+1;
2705 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2706 STRLENOF("serialNumber")) == 0 ))
2708 /* parse serialNumber */
2710 x.bv_val += STRLENOF("serialNumber");
2711 x.bv_len -= STRLENOF("serialNumber");
2713 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2714 x.bv_val++; x.bv_len--;
2716 /* eat leading spaces */
2717 for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2721 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2722 x.bv_val++; x.bv_len--;
2724 sn.bv_val = x.bv_val;
2727 if( sn.bv_val[0] == '-' ) {
2732 for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2733 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2736 if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2737 if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2738 return LDAP_INVALID_SYNTAX;
2741 x.bv_val += sn.bv_len;
2742 x.bv_len -= sn.bv_len;
2744 } else return LDAP_INVALID_SYNTAX;
2746 /* eat trailing spaces */
2747 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2751 /* should have no characters left... */
2752 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
2755 /* validate DN -- doesn't handle double dquote */
2756 rc = dnValidate( NULL, &i );
2757 if( rc ) return LDAP_INVALID_SYNTAX;
2759 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: OKAY\n",
2761 return LDAP_SUCCESS;
2765 serialNumberAndIssuerPretty(
2773 struct berval sn, i, ni;
2775 assert( in != NULL );
2776 assert( out != NULL );
2778 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
2781 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2783 if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2784 /* Parse old format */
2785 i.bv_val = ber_bvchr( in, '$' );
2786 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2788 sn.bv_val = in->bv_val;
2789 sn.bv_len = i.bv_val - in->bv_val;
2792 i.bv_len = in->bv_len - (sn.bv_len + 1);
2794 /* eat leading zeros */
2795 for( n=0; n < (sn.bv_len-1); n++ ) {
2796 if( sn.bv_val[n] != '0' ) break;
2801 for( n=0; n < sn.bv_len; n++ ) {
2802 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2806 /* Parse GSER format */
2807 int havesn=0,haveissuer=0;
2808 struct berval x = *in;
2812 /* eat leading spaces */
2813 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2817 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2818 return LDAP_INVALID_SYNTAX;
2821 /* should be at issuer or serialNumber NamedValue */
2822 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2824 x.bv_val += STRLENOF("issuer");
2825 x.bv_len -= STRLENOF("issuer");
2827 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2828 x.bv_val++; x.bv_len--;
2830 /* eat leading spaces */
2831 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2835 if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2836 x.bv_val++; x.bv_len--;
2838 i.bv_val = x.bv_val;
2841 for( ; i.bv_len < x.bv_len; ) {
2842 if ( i.bv_val[i.bv_len] != '"' ) {
2846 if ( i.bv_val[i.bv_len+1] == '"' ) {
2853 x.bv_val += i.bv_len+1;
2854 x.bv_len -= i.bv_len+1;
2856 if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2857 return LDAP_INVALID_SYNTAX;
2862 } else if( strncasecmp( x.bv_val, "serialNumber",
2863 STRLENOF("serialNumber")) == 0 )
2865 /* parse serialNumber */
2867 x.bv_val += STRLENOF("serialNumber");
2868 x.bv_len -= STRLENOF("serialNumber");
2870 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2871 x.bv_val++; x.bv_len--;
2873 /* eat leading spaces */
2874 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2878 sn.bv_val = x.bv_val;
2881 if( sn.bv_val[0] == '-' ) {
2886 for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2887 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2890 if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2891 if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2892 return LDAP_INVALID_SYNTAX;
2895 x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
2897 if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2898 return LDAP_INVALID_SYNTAX;
2903 } else return LDAP_INVALID_SYNTAX;
2905 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2906 x.bv_val++; x.bv_len--;
2909 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2913 /* should be at remaining NamedValue */
2914 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2915 STRLENOF("issuer" )) == 0 ))
2918 x.bv_val += STRLENOF("issuer");
2919 x.bv_len -= STRLENOF("issuer");
2921 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2922 x.bv_val++; x.bv_len--;
2924 /* eat leading spaces */
2925 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2929 if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2930 x.bv_val++; x.bv_len--;
2932 i.bv_val = x.bv_val;
2935 for( ; i.bv_len < x.bv_len; ) {
2936 if ( i.bv_val[i.bv_len] != '"' ) {
2940 if ( i.bv_val[i.bv_len+1] == '"' ) {
2947 x.bv_val += i.bv_len+1;
2948 x.bv_len -= i.bv_len+1;
2950 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2951 STRLENOF("serialNumber")) == 0 ))
2953 /* parse serialNumber */
2955 x.bv_val += STRLENOF("serialNumber");
2956 x.bv_len -= STRLENOF("serialNumber");
2958 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2959 x.bv_val++; x.bv_len--;
2961 /* eat leading spaces */
2962 for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2966 sn.bv_val = x.bv_val;
2969 if( sn.bv_val[0] == '-' ) {
2974 for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2975 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2978 if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2979 if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2980 return LDAP_INVALID_SYNTAX;
2983 x.bv_val += sn.bv_len;
2984 x.bv_len -= sn.bv_len;
2986 } else return LDAP_INVALID_SYNTAX;
2988 /* eat trailing spaces */
2989 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2993 /* should have no characters left... */
2994 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
2996 ber_dupbv_x( &ni, &i, ctx );
2999 /* need to handle double dquotes here */
3002 rc = dnPretty( syntax, &i, &ni, ctx );
3004 if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3005 slap_sl_free( i.bv_val, ctx );
3008 if( rc ) return LDAP_INVALID_SYNTAX;
3010 /* make room from sn + "$" */
3011 out->bv_len = STRLENOF("{ serialNumber , issuer \"\" }")
3012 + sn.bv_len + ni.bv_len;
3013 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3015 if( out->bv_val == NULL ) {
3017 slap_sl_free( ni.bv_val, ctx );
3022 AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3023 STRLENOF("{ serialNumber "));
3024 n = STRLENOF("{ serialNumber ");
3026 AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3029 AC_MEMCPY( &out->bv_val[n], ", issuer \"", STRLENOF(", issuer \""));
3030 n += STRLENOF(", issuer \"");
3032 AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3035 AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF("\" }"));
3036 n += STRLENOF("\" }");
3038 out->bv_val[n] = '\0';
3040 assert( n == out->bv_len );
3042 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
3043 out->bv_val, 0, 0 );
3045 slap_sl_free( ni.bv_val, ctx );
3047 return LDAP_SUCCESS;
3051 * This routine is called by certificateExactNormalize when
3052 * certificateExactNormalize receives a search string instead of
3053 * a certificate. This routine checks if the search value is valid
3054 * and then returns the normalized value
3057 serialNumberAndIssuerNormalize(
3067 struct berval sn, i, ni;
3069 assert( in != NULL );
3070 assert( out != NULL );
3072 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3075 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3077 if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3078 /* Parse old format */
3079 i.bv_val = ber_bvchr( in, '$' );
3080 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
3082 sn.bv_val = in->bv_val;
3083 sn.bv_len = i.bv_val - in->bv_val;
3086 i.bv_len = in->bv_len - (sn.bv_len + 1);
3088 /* eat leading zeros */
3089 for( n=0; n < (sn.bv_len-1); n++ ) {
3090 if( sn.bv_val[n] != '0' ) break;
3095 for( n=0; n < sn.bv_len; n++ ) {
3096 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3100 /* Parse GSER format */
3101 int havesn=0,haveissuer=0;
3102 struct berval x = *in;
3106 /* eat leading spaces */
3107 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3111 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
3112 return LDAP_INVALID_SYNTAX;
3115 /* should be at issuer or serialNumber NamedValue */
3116 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
3118 x.bv_val += STRLENOF("issuer");
3119 x.bv_len -= STRLENOF("issuer");
3121 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3122 x.bv_val++; x.bv_len--;
3124 /* eat leading spaces */
3125 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3129 if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3130 x.bv_val++; x.bv_len--;
3132 i.bv_val = x.bv_val;
3135 for( ; i.bv_len < x.bv_len; ) {
3136 if ( i.bv_val[i.bv_len] != '"' ) {
3140 if ( i.bv_val[i.bv_len+1] == '"' ) {
3147 x.bv_val += i.bv_len+1;
3148 x.bv_len -= i.bv_len+1;
3150 if ( x.bv_len < STRLENOF(",serialNumber 0")) {
3151 return LDAP_INVALID_SYNTAX;
3156 } else if( strncasecmp( x.bv_val, "serialNumber",
3157 STRLENOF("serialNumber")) == 0 )
3159 /* parse serialNumber */
3161 x.bv_val += STRLENOF("serialNumber");
3162 x.bv_len -= STRLENOF("serialNumber");
3164 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3165 x.bv_val++; x.bv_len--;
3167 /* eat leading spaces */
3168 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3172 sn.bv_val = x.bv_val;
3175 if( sn.bv_val[0] == '-' ) {
3180 for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
3181 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
3184 if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
3185 if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
3186 return LDAP_INVALID_SYNTAX;
3189 x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
3191 if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
3192 return LDAP_INVALID_SYNTAX;
3197 } else return LDAP_INVALID_SYNTAX;
3199 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
3200 x.bv_val++; x.bv_len--;
3203 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3207 /* should be at remaining NamedValue */
3208 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
3209 STRLENOF("issuer" )) == 0 ))
3212 x.bv_val += STRLENOF("issuer");
3213 x.bv_len -= STRLENOF("issuer");
3215 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3216 x.bv_val++; x.bv_len--;
3218 /* eat leading spaces */
3219 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3223 if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3224 x.bv_val++; x.bv_len--;
3226 i.bv_val = x.bv_val;
3229 for( ; i.bv_len < x.bv_len; ) {
3230 if ( i.bv_val[i.bv_len] != '"' ) {
3234 if ( i.bv_val[i.bv_len+1] == '"' ) {
3241 x.bv_val += i.bv_len+1;
3242 x.bv_len -= i.bv_len+1;
3244 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
3245 STRLENOF("serialNumber")) == 0 ))
3247 /* parse serialNumber */
3249 x.bv_val += STRLENOF("serialNumber");
3250 x.bv_len -= STRLENOF("serialNumber");
3252 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3253 x.bv_val++; x.bv_len--;
3255 /* eat leading spaces */
3256 for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
3260 sn.bv_val = x.bv_val;
3263 if( sn.bv_val[0] == '-' ) {
3268 for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
3269 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
3272 if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
3273 if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
3274 return LDAP_INVALID_SYNTAX;
3277 x.bv_val += sn.bv_len;
3278 x.bv_len -= sn.bv_len;
3280 } else return LDAP_INVALID_SYNTAX;
3282 /* eat trailing spaces */
3283 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3287 /* should have no characters left... */
3288 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
3290 ber_dupbv_x( &ni, &i, ctx );
3293 /* need to handle double dquotes here */
3296 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3298 if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3299 slap_sl_free( i.bv_val, ctx );
3302 if( rc ) return LDAP_INVALID_SYNTAX;
3304 /* make room from sn + "$" */
3305 out->bv_len = STRLENOF( "{ serialNumber , issuer \"\" }" )
3306 + sn.bv_len + ni.bv_len;
3307 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3309 if( out->bv_val == NULL ) {
3311 slap_sl_free( ni.bv_val, ctx );
3316 AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3317 STRLENOF( "{ serialNumber " ));
3318 n = STRLENOF( "{ serialNumber " );
3320 AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3323 AC_MEMCPY( &out->bv_val[n], ", issuer \"", STRLENOF( ", issuer \"" ));
3324 n += STRLENOF( ", issuer \"" );
3326 AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3329 AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF( "\" }" ));
3330 n += STRLENOF( "\" }" );
3332 out->bv_val[n] = '\0';
3334 assert( n == out->bv_len );
3336 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
3337 out->bv_val, 0, 0 );
3339 slap_sl_free( ni.bv_val, ctx );
3341 return LDAP_SUCCESS;
3345 certificateExactNormalize(
3350 struct berval *normalized,
3353 BerElementBuffer berbuf;
3354 BerElement *ber = (BerElement *)&berbuf;
3358 char serialbuf[64], *serial = serialbuf;
3359 ber_len_t seriallen;
3360 struct berval issuer_dn = BER_BVNULL, bvdn;
3362 int rc = LDAP_INVALID_SYNTAX;
3364 if( BER_BVISEMPTY( val ) ) goto done;
3366 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3367 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
3370 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3372 ber_init2( ber, val, LBER_USE_DER );
3373 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
3374 tag = ber_skip_tag( ber, &len ); /* Sequence */
3375 tag = ber_peek_tag( ber, &len ); /* Optional version? */
3376 if ( tag == SLAP_X509_OPT_C_VERSION ) {
3377 tag = ber_skip_tag( ber, &len );
3378 tag = ber_get_int( ber, &i ); /* version */
3381 /* NOTE: move the test here from certificateNormalize,
3382 * so that we can validate certs with serial longer
3383 * than sizeof(ber_int_t) */
3384 tag = ber_peek_tag( ber, &len ); /* serial */
3385 if ( len > sizeof(ber_int_t) ) {
3388 tag = ber_skip_tag( ber, &len );
3389 ptr = (unsigned char *)ber->ber_ptr;
3390 ber_skip_data( ber, len );
3392 while ( ptr[0] == '\0' && len > 0 ) {
3397 #if defined(USE_MP_BIGNUM)
3400 #elif defined(USE_MP_GMP)
3402 /* hint: use mpz_import(), mpz_get_str() */
3404 #elif defined(USE_MP_LONG_LONG)
3405 if ( len <= sizeof( unsigned long long ) ) {
3406 unsigned long long sn = 0;
3411 for ( i = 1; i < len; i++ ) {
3416 seriallen = snprintf( serialbuf, sizeof(serialbuf), "%llu", sn );
3419 /* do not accept serialNumber that requires
3420 * more than long long */
3421 rc = LDAP_INVALID_SYNTAX;
3426 /* do not accept serialNumber that requires
3428 rc = LDAP_INVALID_SYNTAX;
3433 tag = ber_get_int( ber, &i ); /* serial */
3434 seriallen = snprintf( serialbuf, sizeof(serialbuf), "%d", i );
3436 tag = ber_skip_tag( ber, &len ); /* SignatureAlg */
3437 ber_skip_data( ber, len );
3438 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
3439 len = ber_ptrlen( ber );
3440 bvdn.bv_val = val->bv_val + len;
3441 bvdn.bv_len = val->bv_len - len;
3443 rc = dnX509normalize( &bvdn, &issuer_dn );
3444 if( rc != LDAP_SUCCESS ) goto done;
3446 normalized->bv_len = STRLENOF( "{ serialNumber , issuer \"\" }" )
3447 + seriallen + issuer_dn.bv_len;
3448 normalized->bv_val = ch_malloc(normalized->bv_len+1);
3450 p = (unsigned char *)normalized->bv_val;
3452 AC_MEMCPY(p, "{ serialNumber ", STRLENOF( "{ serialNumber " ));
3453 p += STRLENOF( "{ serialNumber " );
3455 AC_MEMCPY(p, serial, seriallen);
3458 AC_MEMCPY(p, ", issuer \"", STRLENOF( ", issuer \"" ));
3459 p += STRLENOF( ", issuer \"" );
3461 AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
3462 p += issuer_dn.bv_len;
3464 AC_MEMCPY(p, "\" }", STRLENOF( "\" }" ));
3465 p += STRLENOF( "\" }" );
3469 Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
3470 normalized->bv_val, NULL, NULL );
3475 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3476 if ( serial != serialbuf ) ber_memfree_x( serial, ctx );
3482 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
3483 /* slight optimization - does not need the start parameter */
3484 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
3489 check_time_syntax (struct berval *val,
3492 struct berval *fraction)
3495 * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
3496 * start=1 UTCTime YYmmddHHMM[SS][Z|(+/-)HHMM]
3497 * GeneralizedTime supports leap seconds, UTCTime does not.
3499 static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
3500 static const int mdays[2][12] = {
3501 /* non-leap years */
3502 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
3504 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
3507 int part, c, c1, c2, tzoffset, leapyear = 0;
3510 e = p + val->bv_len;
3512 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3513 parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
3515 for (part = start; part < 7 && p < e; part++) {
3517 if (!ASCII_DIGIT(c1)) {
3522 return LDAP_INVALID_SYNTAX;
3525 if (!ASCII_DIGIT(c)) {
3526 return LDAP_INVALID_SYNTAX;
3528 c += c1 * 10 - '0' * 11;
3529 if ((part | 1) == 3) {
3532 return LDAP_INVALID_SYNTAX;
3535 if (c >= ceiling[part]) {
3536 if (! (c == 60 && part == 6 && start == 0))
3537 return LDAP_INVALID_SYNTAX;
3541 if (part < 5 + start) {
3542 return LDAP_INVALID_SYNTAX;
3544 for (; part < 9; part++) {
3548 /* leapyear check for the Gregorian calendar (year>1581) */
3549 if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
3553 if (parts[3] >= mdays[leapyear][parts[2]]) {
3554 return LDAP_INVALID_SYNTAX;
3558 fraction->bv_val = p;
3559 fraction->bv_len = 0;
3560 if (p < e && (*p == '.' || *p == ',')) {
3562 while (++p < e && ASCII_DIGIT(*p)) {
3565 if (p - fraction->bv_val == 1) {
3566 return LDAP_INVALID_SYNTAX;
3568 for (end_num = p; end_num[-1] == '0'; --end_num) {
3571 c = end_num - fraction->bv_val;
3572 if (c != 1) fraction->bv_len = c;
3578 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3584 return LDAP_INVALID_SYNTAX;
3590 for (part = 7; part < 9 && p < e; part++) {
3592 if (!ASCII_DIGIT(c1)) {
3597 return LDAP_INVALID_SYNTAX;
3600 if (!ASCII_DIGIT(c2)) {
3601 return LDAP_INVALID_SYNTAX;
3603 parts[part] = c1 * 10 + c2 - '0' * 11;
3604 if (parts[part] >= ceiling[part]) {
3605 return LDAP_INVALID_SYNTAX;
3608 if (part < 8 + start) {
3609 return LDAP_INVALID_SYNTAX;
3612 if (tzoffset == '-') {
3613 /* negative offset to UTC, ie west of Greenwich */
3614 parts[4] += parts[7];
3615 parts[5] += parts[8];
3616 /* offset is just hhmm, no seconds */
3617 for (part = 6; --part >= 0; ) {
3621 c = mdays[leapyear][parts[2]];
3623 if (parts[part] >= c) {
3625 return LDAP_INVALID_SYNTAX;
3630 } else if (part != 5) {
3635 /* positive offset to UTC, ie east of Greenwich */
3636 parts[4] -= parts[7];
3637 parts[5] -= parts[8];
3638 for (part = 6; --part >= 0; ) {
3639 if (parts[part] < 0) {
3641 return LDAP_INVALID_SYNTAX;
3646 /* make first arg to % non-negative */
3647 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
3652 } else if (part != 5) {
3659 return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3662 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3669 struct berval *normalized )
3673 rc = check_time_syntax(val, 1, parts, NULL);
3674 if (rc != LDAP_SUCCESS) {
3678 normalized->bv_val = ch_malloc( 14 );
3679 if ( normalized->bv_val == NULL ) {
3680 return LBER_ERROR_MEMORY;
3683 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
3684 parts[1], parts[2] + 1, parts[3] + 1,
3685 parts[4], parts[5], parts[6] );
3686 normalized->bv_len = 13;
3688 return LDAP_SUCCESS;
3698 return check_time_syntax(in, 1, parts, NULL);
3701 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
3704 generalizedTimeValidate(
3709 struct berval fraction;
3710 return check_time_syntax(in, 0, parts, &fraction);
3714 generalizedTimeNormalize(
3719 struct berval *normalized,
3724 struct berval fraction;
3726 rc = check_time_syntax(val, 0, parts, &fraction);
3727 if (rc != LDAP_SUCCESS) {
3731 len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
3732 normalized->bv_val = slap_sl_malloc( len + 1, ctx );
3733 if ( BER_BVISNULL( normalized ) ) {
3734 return LBER_ERROR_MEMORY;
3737 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
3738 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
3739 parts[4], parts[5], parts[6] );
3740 if ( !BER_BVISEMPTY( &fraction ) ) {
3741 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
3742 fraction.bv_val, fraction.bv_len );
3743 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
3745 strcpy( normalized->bv_val + len-1, "Z" );
3746 normalized->bv_len = len;
3748 return LDAP_SUCCESS;
3752 generalizedTimeOrderingMatch(
3757 struct berval *value,
3758 void *assertedValue )
3760 struct berval *asserted = (struct berval *) assertedValue;
3761 ber_len_t v_len = value->bv_len;
3762 ber_len_t av_len = asserted->bv_len;
3764 /* ignore trailing 'Z' when comparing */
3765 int match = memcmp( value->bv_val, asserted->bv_val,
3766 (v_len < av_len ? v_len : av_len) - 1 );
3767 if ( match == 0 ) match = v_len - av_len;
3770 return LDAP_SUCCESS;
3773 /* Index generation function */
3774 int generalizedTimeIndexer(
3779 struct berval *prefix,
3787 BerValue bvtmp; /* 40 bit index */
3789 struct lutil_timet tt;
3791 bvtmp.bv_len = sizeof(tmp);
3793 for( i=0; values[i].bv_val != NULL; i++ ) {
3794 /* just count them */
3797 /* we should have at least one value at this point */
3800 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
3802 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
3803 for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
3804 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
3805 /* Use 40 bits of time for key */
3806 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
3807 lutil_tm2time( &tm, &tt );
3808 tmp[0] = tt.tt_gsec & 0xff;
3809 tmp[4] = tt.tt_sec & 0xff;
3811 tmp[3] = tt.tt_sec & 0xff;
3813 tmp[2] = tt.tt_sec & 0xff;
3815 tmp[1] = tt.tt_sec & 0xff;
3817 ber_dupbv_x(&keys[j++], &bvtmp, ctx );
3821 keys[j].bv_val = NULL;
3826 return LDAP_SUCCESS;
3829 /* Index generation function */
3830 int generalizedTimeFilter(
3835 struct berval *prefix,
3836 void * assertedValue,
3842 BerValue bvtmp; /* 40 bit index */
3843 BerValue *value = (BerValue *) assertedValue;
3845 struct lutil_timet tt;
3847 bvtmp.bv_len = sizeof(tmp);
3849 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
3850 /* Use 40 bits of time for key */
3851 if ( value->bv_val && value->bv_len >= 10 &&
3852 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
3854 lutil_tm2time( &tm, &tt );
3855 tmp[0] = tt.tt_gsec & 0xff;
3856 tmp[4] = tt.tt_sec & 0xff;
3858 tmp[3] = tt.tt_sec & 0xff;
3860 tmp[2] = tt.tt_sec & 0xff;
3862 tmp[1] = tt.tt_sec & 0xff;
3864 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
3865 ber_dupbv_x(keys, &bvtmp, ctx );
3866 keys[1].bv_val = NULL;
3874 return LDAP_SUCCESS;
3878 deliveryMethodValidate(
3880 struct berval *val )
3883 #define LENOF(s) (sizeof(s)-1)
3884 struct berval tmp = *val;
3886 * DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
3887 * pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
3888 * "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
3891 if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3893 switch( tmp.bv_val[0] ) {
3896 if(( tmp.bv_len >= LENOF("any") ) &&
3897 ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
3899 tmp.bv_len -= LENOF("any");
3900 tmp.bv_val += LENOF("any");
3903 return LDAP_INVALID_SYNTAX;
3907 if(( tmp.bv_len >= LENOF("mhs") ) &&
3908 ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
3910 tmp.bv_len -= LENOF("mhs");
3911 tmp.bv_val += LENOF("mhs");
3914 return LDAP_INVALID_SYNTAX;
3918 if(( tmp.bv_len >= LENOF("physical") ) &&
3919 ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
3921 tmp.bv_len -= LENOF("physical");
3922 tmp.bv_val += LENOF("physical");
3925 return LDAP_INVALID_SYNTAX;
3928 case 'T': /* telex or teletex or telephone */
3929 if(( tmp.bv_len >= LENOF("telex") ) &&
3930 ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
3932 tmp.bv_len -= LENOF("telex");
3933 tmp.bv_val += LENOF("telex");
3936 if(( tmp.bv_len >= LENOF("teletex") ) &&
3937 ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
3939 tmp.bv_len -= LENOF("teletex");
3940 tmp.bv_val += LENOF("teletex");
3943 if(( tmp.bv_len >= LENOF("telephone") ) &&
3944 ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
3946 tmp.bv_len -= LENOF("telephone");
3947 tmp.bv_val += LENOF("telephone");
3950 return LDAP_INVALID_SYNTAX;
3953 case 'G': /* g3fax or g4fax */
3954 if(( tmp.bv_len >= LENOF("g3fax") ) && (
3955 ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
3956 ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
3958 tmp.bv_len -= LENOF("g3fax");
3959 tmp.bv_val += LENOF("g3fax");
3962 return LDAP_INVALID_SYNTAX;
3966 if(( tmp.bv_len >= LENOF("ia5") ) &&
3967 ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
3969 tmp.bv_len -= LENOF("ia5");
3970 tmp.bv_val += LENOF("ia5");
3973 return LDAP_INVALID_SYNTAX;
3977 if(( tmp.bv_len >= LENOF("videotex") ) &&
3978 ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
3980 tmp.bv_len -= LENOF("videotex");
3981 tmp.bv_val += LENOF("videotex");
3984 return LDAP_INVALID_SYNTAX;
3987 return LDAP_INVALID_SYNTAX;
3990 if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
3992 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3996 if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
4000 return LDAP_INVALID_SYNTAX;
4002 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4011 nisNetgroupTripleValidate(
4013 struct berval *val )
4018 if ( BER_BVISEMPTY( val ) ) {
4019 return LDAP_INVALID_SYNTAX;
4022 p = (char *)val->bv_val;
4023 e = p + val->bv_len;
4025 if ( *p != '(' /*')'*/ ) {
4026 return LDAP_INVALID_SYNTAX;
4029 for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
4033 return LDAP_INVALID_SYNTAX;
4036 } else if ( !AD_CHAR( *p ) ) {
4037 return LDAP_INVALID_SYNTAX;
4041 if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
4042 return LDAP_INVALID_SYNTAX;
4048 return LDAP_INVALID_SYNTAX;
4051 return LDAP_SUCCESS;
4055 bootParameterValidate(
4057 struct berval *val )
4061 if ( BER_BVISEMPTY( val ) ) {
4062 return LDAP_INVALID_SYNTAX;
4065 p = (char *)val->bv_val;
4066 e = p + val->bv_len;
4069 for (; ( p < e ) && ( *p != '=' ); p++ ) {
4070 if ( !AD_CHAR( *p ) ) {
4071 return LDAP_INVALID_SYNTAX;
4076 return LDAP_INVALID_SYNTAX;
4080 for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
4081 if ( !AD_CHAR( *p ) ) {
4082 return LDAP_INVALID_SYNTAX;
4087 return LDAP_INVALID_SYNTAX;
4091 for ( p++; p < e; p++ ) {
4092 if ( !SLAP_PRINTABLE( *p ) ) {
4093 return LDAP_INVALID_SYNTAX;
4097 return LDAP_SUCCESS;
4101 firstComponentNormalize(
4106 struct berval *normalized,
4113 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
4114 ber_dupbv_x( normalized, val, ctx );
4115 return LDAP_SUCCESS;
4118 if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4120 if( val->bv_val[0] != '(' /*')'*/ &&
4121 val->bv_val[0] != '{' /*'}'*/ )
4123 return LDAP_INVALID_SYNTAX;
4126 /* trim leading white space */
4128 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
4134 /* grab next word */
4135 comp.bv_val = &val->bv_val[len];
4136 len = val->bv_len - len;
4137 for( comp.bv_len = 0;
4138 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
4144 if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
4145 rc = numericoidValidate( NULL, &comp );
4146 } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
4147 rc = integerValidate( NULL, &comp );
4149 rc = LDAP_INVALID_SYNTAX;
4153 if( rc == LDAP_SUCCESS ) {
4154 ber_dupbv_x( normalized, &comp, ctx );
4160 static char *country_gen_syn[] = {
4161 "1.3.6.1.4.1.1466.115.121.1.15",
4162 "1.3.6.1.4.1.1466.115.121.1.26",
4163 "1.3.6.1.4.1.1466.115.121.1.44",
4167 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
4168 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
4170 static slap_syntax_defs_rec syntax_defs[] = {
4171 {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
4172 X_BINARY X_NOT_H_R ")",
4173 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
4174 {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
4175 0, NULL, NULL, NULL},
4176 {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
4177 0, NULL, NULL, NULL},
4178 {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
4180 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4181 {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
4183 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4184 {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
4185 0, NULL, bitStringValidate, NULL },
4186 {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
4187 0, NULL, booleanValidate, NULL},
4188 {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
4189 X_BINARY X_NOT_H_R ")",
4190 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4191 NULL, certificateValidate, NULL},
4192 {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
4193 X_BINARY X_NOT_H_R ")",
4194 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4195 NULL, certificateListValidate, NULL},
4196 {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4197 X_BINARY X_NOT_H_R ")",
4198 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4199 NULL, sequenceValidate, NULL},
4200 #if 0 /* need to go __after__ printableString */
4201 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4202 0, "1.3.6.1.4.1.1466.115.121.1.44",
4203 countryStringValidate, NULL},
4205 {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4206 0, NULL, dnValidate, dnPretty},
4207 {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
4208 0, NULL, rdnValidate, rdnPretty},
4209 #ifdef LDAP_COMP_MATCH
4210 {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
4211 0, NULL, allComponentsValidate, NULL},
4212 {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
4213 0, NULL, componentFilterValidate, NULL},
4215 {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4216 0, NULL, NULL, NULL},
4217 {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4218 0, NULL, deliveryMethodValidate, NULL},
4219 {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4220 0, NULL, UTF8StringValidate, NULL},
4221 {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4222 0, NULL, NULL, NULL},
4223 {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4224 0, NULL, NULL, NULL},
4225 {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4226 0, NULL, NULL, NULL},
4227 {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4228 0, NULL, NULL, NULL},
4229 {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4230 0, NULL, NULL, NULL},
4231 {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4232 0, NULL, printablesStringValidate, NULL},
4233 {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4234 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
4235 {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4236 0, NULL, generalizedTimeValidate, NULL},
4237 {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4238 0, NULL, NULL, NULL},
4239 {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4240 0, NULL, IA5StringValidate, NULL},
4241 {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4242 0, NULL, integerValidate, NULL},
4243 {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4244 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4245 {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4246 0, NULL, NULL, NULL},
4247 {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4248 0, NULL, NULL, NULL},
4249 {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4250 0, NULL, NULL, NULL},
4251 {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4252 0, NULL, NULL, NULL},
4253 {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4254 0, NULL, NULL, NULL},
4255 {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4256 0, NULL, nameUIDValidate, nameUIDPretty },
4257 {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4258 0, NULL, NULL, NULL},
4259 {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4260 0, NULL, numericStringValidate, NULL},
4261 {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4262 0, NULL, NULL, NULL},
4263 {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4264 0, NULL, numericoidValidate, NULL},
4265 {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4266 0, NULL, IA5StringValidate, NULL},
4267 {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4268 0, NULL, blobValidate, NULL},
4269 {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4270 0, NULL, UTF8StringValidate, NULL},
4271 {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4272 0, NULL, NULL, NULL},
4273 {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4274 0, NULL, NULL, NULL},
4275 {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4276 0, NULL, printableStringValidate, NULL},
4277 /* moved here because now depends on Directory String, IA5 String
4278 * and Printable String */
4279 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4280 0, country_gen_syn, countryStringValidate, NULL},
4281 {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
4282 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
4283 0, NULL, subtreeSpecificationValidate, NULL},
4284 {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4285 X_BINARY X_NOT_H_R ")",
4286 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4287 {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4288 0, NULL, printableStringValidate, NULL},
4289 {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4290 0, NULL, NULL, NULL},
4291 {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4292 0, NULL, printablesStringValidate, NULL},
4293 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4294 {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4295 0, NULL, utcTimeValidate, NULL},
4297 {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4298 0, NULL, NULL, NULL},
4299 {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4300 0, NULL, NULL, NULL},
4301 {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4302 0, NULL, NULL, NULL},
4303 {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4304 0, NULL, NULL, NULL},
4305 {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4306 0, NULL, NULL, NULL},
4308 /* RFC 2307 NIS Syntaxes */
4309 {"( 1.3.6.1.1.1.0.0 DESC 'RFC2307 NIS Netgroup Triple' )",
4310 0, NULL, nisNetgroupTripleValidate, NULL},
4311 {"( 1.3.6.1.1.1.0.1 DESC 'RFC2307 Boot Parameter' )",
4312 0, NULL, bootParameterValidate, NULL},
4314 /* draft-zeilenga-ldap-x509 */
4315 {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
4316 SLAP_SYNTAX_HIDE, NULL,
4317 serialNumberAndIssuerValidate,
4318 serialNumberAndIssuerPretty},
4319 {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
4320 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4321 {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
4322 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4323 {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
4324 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4325 {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
4326 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4327 {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
4328 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4329 {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
4330 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4332 #ifdef SLAPD_AUTHPASSWD
4333 /* needs updating */
4334 {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4335 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4338 {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
4339 0, NULL, UUIDValidate, UUIDPretty},
4341 {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
4342 SLAP_SYNTAX_HIDE, NULL, csnValidate, NULL},
4344 /* OpenLDAP Void Syntax */
4345 {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4346 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
4348 /* FIXME: OID is unused, but not registered yet */
4349 {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
4350 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
4352 {NULL, 0, NULL, NULL, NULL}
4355 char *certificateExactMatchSyntaxes[] = {
4356 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4359 #ifdef LDAP_COMP_MATCH
4360 char *componentFilterMatchSyntaxes[] = {
4361 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4365 char *directoryStringSyntaxes[] = {
4366 "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
4369 char *integerFirstComponentMatchSyntaxes[] = {
4370 "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
4371 "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
4374 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
4375 "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
4376 "1.3.6.1.4.1.1466.115.121.1.3" /* attributeTypeDescription */,
4377 "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
4378 "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
4379 "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
4380 "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
4381 "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
4382 "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
4387 * Other matching rules in X.520 that we do not use (yet):
4389 * 2.5.13.25 uTCTimeMatch
4390 * 2.5.13.26 uTCTimeOrderingMatch
4391 * 2.5.13.31* directoryStringFirstComponentMatch
4392 * 2.5.13.32* wordMatch
4393 * 2.5.13.33* keywordMatch
4394 * 2.5.13.36+ certificatePairExactMatch
4395 * 2.5.13.37+ certificatePairMatch
4396 * 2.5.13.38+ certificateListExactMatch
4397 * 2.5.13.39+ certificateListMatch
4398 * 2.5.13.40+ algorithmIdentifierMatch
4399 * 2.5.13.41* storedPrefixMatch
4400 * 2.5.13.42 attributeCertificateMatch
4401 * 2.5.13.43 readerAndKeyIDMatch
4402 * 2.5.13.44 attributeIntegrityMatch
4404 * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
4405 * (+) described in draft-zeilenga-ldap-x509
4407 static slap_mrule_defs_rec mrule_defs[] = {
4409 * EQUALITY matching rules must be listed after associated APPROX
4410 * matching rules. So, we list all APPROX matching rules first.
4412 {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4413 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4414 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4415 NULL, NULL, directoryStringApproxMatch,
4416 directoryStringApproxIndexer, directoryStringApproxFilter,
4419 {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4420 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4421 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4422 NULL, NULL, IA5StringApproxMatch,
4423 IA5StringApproxIndexer, IA5StringApproxFilter,
4427 * Other matching rules
4430 {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4431 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4432 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4433 NULL, NULL, octetStringMatch,
4434 octetStringIndexer, octetStringFilter,
4437 {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4438 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4439 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4440 NULL, dnNormalize, dnMatch,
4441 octetStringIndexer, octetStringFilter,
4444 {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
4445 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4446 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4447 NULL, dnNormalize, dnRelativeMatch,
4451 {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
4452 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4453 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4454 NULL, dnNormalize, dnRelativeMatch,
4458 {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
4459 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4460 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4461 NULL, dnNormalize, dnRelativeMatch,
4465 {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
4466 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4467 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4468 NULL, dnNormalize, dnRelativeMatch,
4472 {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
4473 "SYNTAX 1.2.36.79672281.1.5.0 )",
4474 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4475 NULL, rdnNormalize, rdnMatch,
4476 octetStringIndexer, octetStringFilter,
4479 #ifdef LDAP_COMP_MATCH
4480 {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
4481 "SYNTAX 1.2.36.79672281.1.5.2 )",
4482 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
4483 NULL, NULL , componentFilterMatch,
4484 octetStringIndexer, octetStringFilter,
4487 {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
4488 "SYNTAX 1.2.36.79672281.1.5.3 )",
4489 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4490 NULL, NULL , allComponentsMatch,
4491 octetStringIndexer, octetStringFilter,
4494 {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
4495 "SYNTAX 1.2.36.79672281.1.5.3 )",
4496 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4497 NULL, NULL , directoryComponentsMatch,
4498 octetStringIndexer, octetStringFilter,
4502 {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4503 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4504 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4505 NULL, UTF8StringNormalize, octetStringMatch,
4506 octetStringIndexer, octetStringFilter,
4507 directoryStringApproxMatchOID },
4509 {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4510 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4511 SLAP_MR_ORDERING, directoryStringSyntaxes,
4512 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4514 "caseIgnoreMatch" },
4516 {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4517 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4518 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4519 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4520 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4521 "caseIgnoreMatch" },
4523 {"( 2.5.13.5 NAME 'caseExactMatch' "
4524 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4525 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4526 NULL, UTF8StringNormalize, octetStringMatch,
4527 octetStringIndexer, octetStringFilter,
4528 directoryStringApproxMatchOID },
4530 {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4531 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4532 SLAP_MR_ORDERING, directoryStringSyntaxes,
4533 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4537 {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4538 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4539 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4540 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4541 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4544 {"( 2.5.13.8 NAME 'numericStringMatch' "
4545 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4546 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4547 NULL, numericStringNormalize, octetStringMatch,
4548 octetStringIndexer, octetStringFilter,
4551 {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
4552 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4553 SLAP_MR_ORDERING, NULL,
4554 NULL, numericStringNormalize, octetStringOrderingMatch,
4556 "numericStringMatch" },
4558 {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4559 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4560 SLAP_MR_SUBSTR, NULL,
4561 NULL, numericStringNormalize, octetStringSubstringsMatch,
4562 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4563 "numericStringMatch" },
4565 {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4566 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4567 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4568 NULL, NULL, NULL, NULL, NULL, NULL },
4570 {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4571 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4572 SLAP_MR_SUBSTR, NULL,
4573 NULL, NULL, NULL, NULL, NULL,
4574 "caseIgnoreListMatch" },
4576 {"( 2.5.13.13 NAME 'booleanMatch' "
4577 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
4578 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4579 NULL, NULL, booleanMatch,
4580 octetStringIndexer, octetStringFilter,
4583 {"( 2.5.13.14 NAME 'integerMatch' "
4584 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4585 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4586 NULL, NULL, integerMatch,
4587 octetStringIndexer, octetStringFilter,
4590 {"( 2.5.13.15 NAME 'integerOrderingMatch' "
4591 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4592 SLAP_MR_ORDERING, NULL,
4593 NULL, NULL, integerMatch,
4597 {"( 2.5.13.16 NAME 'bitStringMatch' "
4598 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
4599 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4600 NULL, NULL, octetStringMatch,
4601 octetStringIndexer, octetStringFilter,
4604 {"( 2.5.13.17 NAME 'octetStringMatch' "
4605 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4606 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4607 NULL, NULL, octetStringMatch,
4608 octetStringIndexer, octetStringFilter,
4611 {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
4612 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4613 SLAP_MR_ORDERING, NULL,
4614 NULL, NULL, octetStringOrderingMatch,
4616 "octetStringMatch" },
4618 {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
4619 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4620 SLAP_MR_SUBSTR, NULL,
4621 NULL, NULL, octetStringSubstringsMatch,
4622 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4623 "octetStringMatch" },
4625 {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
4626 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
4627 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4629 telephoneNumberNormalize, octetStringMatch,
4630 octetStringIndexer, octetStringFilter,
4633 {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
4634 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4635 SLAP_MR_SUBSTR, NULL,
4636 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
4637 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4638 "telephoneNumberMatch" },
4640 {"( 2.5.13.22 NAME 'presentationAddressMatch' "
4641 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
4642 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4643 NULL, NULL, NULL, NULL, NULL, NULL },
4645 {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
4646 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
4647 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4648 NULL, uniqueMemberNormalize, uniqueMemberMatch,
4649 uniqueMemberIndexer, uniqueMemberFilter,
4652 {"( 2.5.13.24 NAME 'protocolInformationMatch' "
4653 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
4654 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4655 NULL, NULL, NULL, NULL, NULL, NULL },
4657 {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
4658 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4659 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
4660 NULL, generalizedTimeNormalize, octetStringMatch,
4661 generalizedTimeIndexer, generalizedTimeFilter,
4664 {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
4665 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4666 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
4667 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
4669 "generalizedTimeMatch" },
4671 {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
4672 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4673 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4674 integerFirstComponentMatchSyntaxes,
4675 NULL, firstComponentNormalize, integerMatch,
4676 octetStringIndexer, octetStringFilter,
4679 {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
4680 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4681 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4682 objectIdentifierFirstComponentMatchSyntaxes,
4683 NULL, firstComponentNormalize, octetStringMatch,
4684 octetStringIndexer, octetStringFilter,
4687 {"( 2.5.13.34 NAME 'certificateExactMatch' "
4688 "SYNTAX 1.3.6.1.1.15.1 )",
4689 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
4690 NULL, certificateExactNormalize, octetStringMatch,
4691 octetStringIndexer, octetStringFilter,
4694 {"( 2.5.13.35 NAME 'certificateMatch' "
4695 "SYNTAX 1.3.6.1.1.15.2 )",
4696 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4697 NULL, NULL, NULL, NULL, NULL,
4700 {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
4701 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4702 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4703 NULL, IA5StringNormalize, octetStringMatch,
4704 octetStringIndexer, octetStringFilter,
4705 IA5StringApproxMatchOID },
4707 {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
4708 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4709 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4710 NULL, IA5StringNormalize, octetStringMatch,
4711 octetStringIndexer, octetStringFilter,
4712 IA5StringApproxMatchOID },
4714 {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
4715 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4716 SLAP_MR_SUBSTR, NULL,
4717 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
4718 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4719 "caseIgnoreIA5Match" },
4721 {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
4722 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4723 SLAP_MR_SUBSTR, NULL,
4724 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
4725 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4726 "caseExactIA5Match" },
4728 #ifdef SLAPD_AUTHPASSWD
4729 /* needs updating */
4730 {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
4731 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4732 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
4733 NULL, NULL, authPasswordMatch,
4738 {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
4739 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4741 NULL, NULL, integerBitAndMatch,
4745 {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
4746 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4748 NULL, NULL, integerBitOrMatch,
4752 {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
4753 "SYNTAX 1.3.6.1.1.16.1 )",
4754 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
4755 NULL, UUIDNormalize, octetStringMatch,
4756 octetStringIndexer, octetStringFilter,
4759 {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
4760 "SYNTAX 1.3.6.1.1.16.1 )",
4761 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
4762 NULL, UUIDNormalize, octetStringOrderingMatch,
4763 octetStringIndexer, octetStringFilter,
4766 {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
4767 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
4768 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
4769 NULL, NULL, csnMatch,
4770 csnIndexer, csnFilter,
4773 {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
4774 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
4775 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
4776 NULL, NULL, csnOrderingMatch,
4780 /* FIXME: OID is unused, but not registered yet */
4781 {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
4782 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
4783 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
4784 NULL, authzNormalize, authzMatch,
4788 {NULL, SLAP_MR_NONE, NULL,
4789 NULL, NULL, NULL, NULL, NULL,
4794 slap_schema_init( void )
4799 /* we should only be called once (from main) */
4800 assert( schema_init_done == 0 );
4802 for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
4803 res = register_syntax( &syntax_defs[i] );
4806 fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
4807 syntax_defs[i].sd_desc );
4812 for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
4813 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
4814 mrule_defs[i].mrd_compat_syntaxes == NULL )
4817 "slap_schema_init: Ignoring unusable matching rule %s\n",
4818 mrule_defs[i].mrd_desc );
4822 res = register_matching_rule( &mrule_defs[i] );
4826 "slap_schema_init: Error registering matching rule %s\n",
4827 mrule_defs[i].mrd_desc );
4832 res = slap_schema_load();
4833 schema_init_done = 1;
4838 schema_destroy( void )
4847 if( schema_init_done ) {
4848 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
4849 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );