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 certificate validation */
102 static int certificateValidate( Syntax *syntax, struct berval *in )
104 BerElementBuffer berbuf;
105 BerElement *ber = (BerElement *)&berbuf;
108 ber_int_t i, version = 0;
110 ber_init2( ber, in, LBER_USE_DER );
111 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
112 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
113 tag = ber_skip_tag( ber, &len ); /* Sequence */
114 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
115 tag = ber_peek_tag( ber, &len );
116 /* Optional version */
118 tag = ber_skip_tag( ber, &len );
119 tag = ber_get_int( ber, &version );
120 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
122 /* NOTE: don't try to parse Serial, because it might be longer
123 * than sizeof(ber_int_t); deferred to certificateExactNormalize() */
124 tag = ber_skip_tag( ber, &len ); /* Serial */
125 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
126 ber_skip_data( ber, len );
127 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
128 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
129 ber_skip_data( ber, len );
130 tag = ber_skip_tag( ber, &len ); /* Issuer DN */
131 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
132 ber_skip_data( ber, len );
133 tag = ber_skip_tag( ber, &len ); /* Validity */
134 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
135 ber_skip_data( ber, len );
136 tag = ber_skip_tag( ber, &len ); /* Subject DN */
137 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
138 ber_skip_data( ber, len );
139 tag = ber_skip_tag( ber, &len ); /* Subject PublicKeyInfo */
140 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
141 ber_skip_data( ber, len );
142 tag = ber_skip_tag( ber, &len );
143 if ( tag == 0xa1 ) { /* issuerUniqueID */
144 if ( version < 1 ) return LDAP_INVALID_SYNTAX;
145 ber_skip_data( ber, len );
146 tag = ber_skip_tag( ber, &len );
148 if ( tag == 0xa2 ) { /* subjectUniqueID */
149 if ( version < 1 ) return LDAP_INVALID_SYNTAX;
150 ber_skip_data( ber, len );
151 tag = ber_skip_tag( ber, &len );
153 if ( tag == 0xa3 ) { /* Extensions */
154 if ( version < 2 ) return LDAP_INVALID_SYNTAX;
155 tag = ber_skip_tag( ber, &len );
156 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
157 ber_skip_data( ber, len );
158 tag = ber_skip_tag( ber, &len );
160 /* signatureAlgorithm */
161 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
162 ber_skip_data( ber, len );
163 tag = ber_skip_tag( ber, &len );
165 if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
166 ber_skip_data( ber, len );
167 tag = ber_skip_tag( ber, &len );
168 /* Must be at end now */
169 if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
179 struct berval *value,
180 void *assertedValue )
182 struct berval *asserted = (struct berval *) assertedValue;
183 int match = value->bv_len - asserted->bv_len;
186 match = memcmp( value->bv_val, asserted->bv_val, value->bv_len );
194 octetStringOrderingMatch(
199 struct berval *value,
200 void *assertedValue )
202 struct berval *asserted = (struct berval *) assertedValue;
203 ber_len_t v_len = value->bv_len;
204 ber_len_t av_len = asserted->bv_len;
206 int match = memcmp( value->bv_val, asserted->bv_val,
207 (v_len < av_len ? v_len : av_len) );
209 if( match == 0 ) match = v_len - av_len;
217 HASH_CONTEXT *HASHcontext,
218 struct berval *prefix,
223 HASH_Init(HASHcontext);
224 if(prefix && prefix->bv_len > 0) {
225 HASH_Update(HASHcontext,
226 (unsigned char *)prefix->bv_val, prefix->bv_len);
228 if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
229 HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
230 HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
236 HASH_CONTEXT *HASHcontext,
237 unsigned char *HASHdigest,
238 unsigned char *value,
241 HASH_CONTEXT ctx = *HASHcontext;
242 HASH_Update( &ctx, value, len );
243 HASH_Final( HASHdigest, &ctx );
246 /* Index generation function */
247 int octetStringIndexer(
252 struct berval *prefix,
260 HASH_CONTEXT HASHcontext;
261 unsigned char HASHdigest[HASH_BYTES];
262 struct berval digest;
263 digest.bv_val = (char *)HASHdigest;
264 digest.bv_len = sizeof(HASHdigest);
266 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
267 /* just count them */
270 /* we should have at least one value at this point */
273 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
275 slen = syntax->ssyn_oidlen;
276 mlen = mr->smr_oidlen;
278 hashPreset( &HASHcontext, prefix, 0, syntax, mr);
279 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
280 hashIter( &HASHcontext, HASHdigest,
281 (unsigned char *)values[i].bv_val, values[i].bv_len );
282 ber_dupbv_x( &keys[i], &digest, ctx );
285 BER_BVZERO( &keys[i] );
292 /* Index generation function */
293 int octetStringFilter(
298 struct berval *prefix,
299 void * assertedValue,
305 HASH_CONTEXT HASHcontext;
306 unsigned char HASHdigest[HASH_BYTES];
307 struct berval *value = (struct berval *) assertedValue;
308 struct berval digest;
309 digest.bv_val = (char *)HASHdigest;
310 digest.bv_len = sizeof(HASHdigest);
312 slen = syntax->ssyn_oidlen;
313 mlen = mr->smr_oidlen;
315 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
317 hashPreset( &HASHcontext, prefix, 0, syntax, mr );
318 hashIter( &HASHcontext, HASHdigest,
319 (unsigned char *)value->bv_val, value->bv_len );
321 ber_dupbv_x( keys, &digest, ctx );
322 BER_BVZERO( &keys[1] );
330 octetStringSubstringsMatch(
335 struct berval *value,
336 void *assertedValue )
339 SubstringsAssertion *sub = assertedValue;
340 struct berval left = *value;
344 /* Add up asserted input length */
345 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
346 inlen += sub->sa_initial.bv_len;
349 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
350 inlen += sub->sa_any[i].bv_len;
353 if ( !BER_BVISNULL( &sub->sa_final ) ) {
354 inlen += sub->sa_final.bv_len;
357 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
358 if ( inlen > left.bv_len ) {
363 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
364 sub->sa_initial.bv_len );
370 left.bv_val += sub->sa_initial.bv_len;
371 left.bv_len -= sub->sa_initial.bv_len;
372 inlen -= sub->sa_initial.bv_len;
375 if ( !BER_BVISNULL( &sub->sa_final ) ) {
376 if ( inlen > left.bv_len ) {
381 match = memcmp( sub->sa_final.bv_val,
382 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
383 sub->sa_final.bv_len );
389 left.bv_len -= sub->sa_final.bv_len;
390 inlen -= sub->sa_final.bv_len;
394 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
399 if ( inlen > left.bv_len ) {
400 /* not enough length */
405 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
409 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
416 idx = p - left.bv_val;
418 if ( idx >= left.bv_len ) {
419 /* this shouldn't happen */
426 if ( sub->sa_any[i].bv_len > left.bv_len ) {
427 /* not enough left */
432 match = memcmp( left.bv_val,
433 sub->sa_any[i].bv_val,
434 sub->sa_any[i].bv_len );
442 left.bv_val += sub->sa_any[i].bv_len;
443 left.bv_len -= sub->sa_any[i].bv_len;
444 inlen -= sub->sa_any[i].bv_len;
453 /* Substrings Index generation function */
455 octetStringSubstringsIndexer(
460 struct berval *prefix,
469 HASH_CONTEXT HCany, HCini, HCfin;
470 unsigned char HASHdigest[HASH_BYTES];
471 struct berval digest;
472 digest.bv_val = (char *)HASHdigest;
473 digest.bv_len = sizeof(HASHdigest);
477 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
478 /* count number of indices to generate */
479 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
480 if( values[i].bv_len >= index_substr_if_maxlen ) {
481 nkeys += index_substr_if_maxlen -
482 (index_substr_if_minlen - 1);
483 } else if( values[i].bv_len >= index_substr_if_minlen ) {
484 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
488 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
489 if( values[i].bv_len >= index_substr_any_len ) {
490 nkeys += values[i].bv_len - (index_substr_any_len - 1);
494 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
495 if( values[i].bv_len >= index_substr_if_maxlen ) {
496 nkeys += index_substr_if_maxlen -
497 (index_substr_if_minlen - 1);
498 } else if( values[i].bv_len >= index_substr_if_minlen ) {
499 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
505 /* no keys to generate */
510 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
512 slen = syntax->ssyn_oidlen;
513 mlen = mr->smr_oidlen;
515 if ( flags & SLAP_INDEX_SUBSTR_ANY )
516 hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
517 if( flags & SLAP_INDEX_SUBSTR_INITIAL )
518 hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
519 if( flags & SLAP_INDEX_SUBSTR_FINAL )
520 hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
523 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
526 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
527 ( values[i].bv_len >= index_substr_any_len ) )
529 max = values[i].bv_len - (index_substr_any_len - 1);
531 for( j=0; j<max; j++ ) {
532 hashIter( &HCany, HASHdigest,
533 (unsigned char *)&values[i].bv_val[j],
534 index_substr_any_len );
535 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
539 /* skip if too short */
540 if( values[i].bv_len < index_substr_if_minlen ) continue;
542 max = index_substr_if_maxlen < values[i].bv_len
543 ? index_substr_if_maxlen : values[i].bv_len;
545 for( j=index_substr_if_minlen; j<=max; j++ ) {
547 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
548 hashIter( &HCini, HASHdigest,
549 (unsigned char *)values[i].bv_val, j );
550 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
553 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
554 hashIter( &HCfin, HASHdigest,
555 (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
556 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
563 BER_BVZERO( &keys[nkeys] );
574 octetStringSubstringsFilter (
579 struct berval *prefix,
580 void * assertedValue,
584 SubstringsAssertion *sa;
587 size_t slen, mlen, klen;
589 HASH_CONTEXT HASHcontext;
590 unsigned char HASHdigest[HASH_BYTES];
591 struct berval *value;
592 struct berval digest;
594 sa = (SubstringsAssertion *) assertedValue;
596 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
597 !BER_BVISNULL( &sa->sa_initial ) &&
598 sa->sa_initial.bv_len >= index_substr_if_minlen )
601 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
602 ( flags & SLAP_INDEX_SUBSTR_ANY ))
604 nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
608 if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
610 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
611 if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
612 /* don't bother accounting with stepping */
613 nkeys += sa->sa_any[i].bv_len -
614 ( index_substr_any_len - 1 );
619 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
620 !BER_BVISNULL( &sa->sa_final ) &&
621 sa->sa_final.bv_len >= index_substr_if_minlen )
624 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
625 ( flags & SLAP_INDEX_SUBSTR_ANY ))
627 nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
636 digest.bv_val = (char *)HASHdigest;
637 digest.bv_len = sizeof(HASHdigest);
639 slen = syntax->ssyn_oidlen;
640 mlen = mr->smr_oidlen;
642 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
645 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
646 !BER_BVISNULL( &sa->sa_initial ) &&
647 sa->sa_initial.bv_len >= index_substr_if_minlen )
649 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
650 value = &sa->sa_initial;
652 klen = index_substr_if_maxlen < value->bv_len
653 ? index_substr_if_maxlen : value->bv_len;
655 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
656 hashIter( &HASHcontext, HASHdigest,
657 (unsigned char *)value->bv_val, klen );
658 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
660 /* If initial is too long and we have subany indexed, use it
661 * to match the excess...
663 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
666 pre = SLAP_INDEX_SUBSTR_PREFIX;
667 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
668 for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
670 hashIter( &HASHcontext, HASHdigest,
671 (unsigned char *)&value->bv_val[j], index_substr_any_len );
672 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
677 if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
679 pre = SLAP_INDEX_SUBSTR_PREFIX;
680 klen = index_substr_any_len;
682 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
683 if( sa->sa_any[i].bv_len < index_substr_any_len ) {
687 value = &sa->sa_any[i];
689 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
691 j <= value->bv_len - index_substr_any_len;
692 j += index_substr_any_step )
694 hashIter( &HASHcontext, HASHdigest,
695 (unsigned char *)&value->bv_val[j], klen );
696 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
701 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
702 !BER_BVISNULL( &sa->sa_final ) &&
703 sa->sa_final.bv_len >= index_substr_if_minlen )
705 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
706 value = &sa->sa_final;
708 klen = index_substr_if_maxlen < value->bv_len
709 ? index_substr_if_maxlen : value->bv_len;
711 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
712 hashIter( &HASHcontext, HASHdigest,
713 (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
714 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
716 /* If final is too long and we have subany indexed, use it
717 * to match the excess...
719 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
722 pre = SLAP_INDEX_SUBSTR_PREFIX;
723 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
724 for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
726 hashIter( &HASHcontext, HASHdigest,
727 (unsigned char *)&value->bv_val[j], index_substr_any_len );
728 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
734 BER_BVZERO( &keys[nkeys] );
751 /* very unforgiving validation, requires no normalization
752 * before simplistic matching
754 if( in->bv_len < 3 ) {
755 return LDAP_INVALID_SYNTAX;
758 /* RFC 4517 Section 3.3.2 Bit String:
759 * BitString = SQUOTE *binary-digit SQUOTE "B"
760 * binary-digit = "0" / "1"
762 * where SQUOTE [RFC4512] is
763 * SQUOTE = %x27 ; single quote ("'")
765 * Example: '0101111101'B
768 if( in->bv_val[0] != '\'' ||
769 in->bv_val[in->bv_len - 2] != '\'' ||
770 in->bv_val[in->bv_len - 1] != 'B' )
772 return LDAP_INVALID_SYNTAX;
775 for( i = in->bv_len - 3; i > 0; i-- ) {
776 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
777 return LDAP_INVALID_SYNTAX;
785 * Syntaxes from RFC 4517
790 A value of the Bit String syntax is a sequence of binary digits. The
791 LDAP-specific encoding of a value of this syntax is defined by the
794 BitString = SQUOTE *binary-digit SQUOTE "B"
796 binary-digit = "0" / "1"
798 The <SQUOTE> rule is defined in [MODELS].
803 The LDAP definition for the Bit String syntax is:
805 ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
807 This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
811 3.3.21. Name and Optional UID
813 A value of the Name and Optional UID syntax is the distinguished name
814 [MODELS] of an entity optionally accompanied by a unique identifier
815 that serves to differentiate the entity from others with an identical
818 The LDAP-specific encoding of a value of this syntax is defined by
821 NameAndOptionalUID = distinguishedName [ SHARP BitString ]
823 The <BitString> rule is defined in Section 3.3.2. The
824 <distinguishedName> rule is defined in [LDAPDN]. The <SHARP> rule is
827 Note that although the '#' character may occur in the string
828 representation of a distinguished name, no additional escaping of
829 this character is performed when a <distinguishedName> is encoded in
830 a <NameAndOptionalUID>.
833 1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
835 The LDAP definition for the Name and Optional UID syntax is:
837 ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
839 This syntax corresponds to the NameAndOptionalUID ASN.1 type from
846 1.4. Common ABNF Productions
849 SHARP = %x23 ; octothorpe (or sharp sign) ("#")
851 SQUOTE = %x27 ; single quote ("'")
855 * Note: normalization strips any leading "0"s, unless the
856 * bit string is exactly "'0'B", so the normalized example,
857 * in slapd, would result in
859 * 1.3.6.1.4.1.1466.0=#04024869,o=test,c=gb#'101'B
861 * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
862 * be escaped except when at the beginning of a value, the
863 * definition of Name and Optional UID appears to be flawed,
864 * because there is no clear means to determine whether the
865 * UID part is present or not.
869 * cn=Someone,dc=example,dc=com#'1'B
871 * could be either a NameAndOptionalUID with trailing UID, i.e.
873 * DN = "cn=Someone,dc=example,dc=com"
876 * or a NameAndOptionalUID with no trailing UID, and the AVA
877 * in the last RDN made of
880 * attributeValue = com#'1'B
882 * in fact "com#'1'B" is a valid IA5 string.
884 * As a consequence, current slapd code assumes that the
885 * presence of portions of a BitString at the end of the string
886 * representation of a NameAndOptionalUID means a BitString
887 * is expected, and cause an error otherwise. This is quite
888 * arbitrary, and might change in the future.
898 struct berval dn, uid;
900 if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
902 ber_dupbv( &dn, in );
903 if( !dn.bv_val ) return LDAP_OTHER;
905 /* if there's a "#", try bitStringValidate()... */
906 uid.bv_val = strrchr( dn.bv_val, '#' );
907 if ( !BER_BVISNULL( &uid ) ) {
909 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
911 rc = bitStringValidate( NULL, &uid );
912 if ( rc == LDAP_SUCCESS ) {
913 /* in case of success, trim the UID,
914 * otherwise treat it as part of the DN */
915 dn.bv_len -= uid.bv_len + 1;
916 uid.bv_val[-1] = '\0';
920 rc = dnValidate( NULL, &dn );
922 ber_memfree( dn.bv_val );
933 assert( val != NULL );
934 assert( out != NULL );
937 Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
939 if( BER_BVISEMPTY( val ) ) {
940 ber_dupbv_x( out, val, ctx );
942 } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
943 return LDAP_INVALID_SYNTAX;
947 struct berval dnval = *val;
948 struct berval uidval = BER_BVNULL;
950 uidval.bv_val = strrchr( val->bv_val, '#' );
951 if ( !BER_BVISNULL( &uidval ) ) {
953 uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
955 rc = bitStringValidate( NULL, &uidval );
957 if ( rc == LDAP_SUCCESS ) {
958 ber_dupbv_x( &dnval, val, ctx );
959 dnval.bv_len -= uidval.bv_len + 1;
960 dnval.bv_val[dnval.bv_len] = '\0';
963 BER_BVZERO( &uidval );
967 rc = dnPretty( syntax, &dnval, out, ctx );
968 if ( dnval.bv_val != val->bv_val ) {
969 slap_sl_free( dnval.bv_val, ctx );
971 if( rc != LDAP_SUCCESS ) {
975 if( !BER_BVISNULL( &uidval ) ) {
979 tmp = slap_sl_realloc( out->bv_val, out->bv_len
980 + STRLENOF( "#" ) + uidval.bv_len + 1,
983 ber_memfree_x( out->bv_val, ctx );
987 out->bv_val[out->bv_len++] = '#';
988 out->bv_val[out->bv_len++] = '\'';
990 got1 = uidval.bv_len < sizeof("'0'B");
991 for( i = 1; i < uidval.bv_len - 2; i++ ) {
992 c = uidval.bv_val[i];
995 if( got1 ) out->bv_val[out->bv_len++] = c;
999 out->bv_val[out->bv_len++] = c;
1004 out->bv_val[out->bv_len++] = '\'';
1005 out->bv_val[out->bv_len++] = 'B';
1006 out->bv_val[out->bv_len] = '\0';
1010 Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1012 return LDAP_SUCCESS;
1016 uniqueMemberNormalize(
1021 struct berval *normalized,
1027 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1029 ber_dupbv_x( &out, val, ctx );
1030 if ( BER_BVISEMPTY( &out ) ) {
1034 struct berval uid = BER_BVNULL;
1036 uid.bv_val = strrchr( out.bv_val, '#' );
1037 if ( !BER_BVISNULL( &uid ) ) {
1039 uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1041 rc = bitStringValidate( NULL, &uid );
1042 if ( rc == LDAP_SUCCESS ) {
1043 uid.bv_val[-1] = '\0';
1044 out.bv_len -= uid.bv_len + 1;
1050 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1052 if( rc != LDAP_SUCCESS ) {
1053 slap_sl_free( out.bv_val, ctx );
1054 return LDAP_INVALID_SYNTAX;
1057 if( !BER_BVISNULL( &uid ) ) {
1060 tmp = ch_realloc( normalized->bv_val,
1061 normalized->bv_len + uid.bv_len
1062 + STRLENOF("#") + 1 );
1063 if ( tmp == NULL ) {
1064 ber_memfree_x( normalized->bv_val, ctx );
1068 normalized->bv_val = tmp;
1070 /* insert the separator */
1071 normalized->bv_val[normalized->bv_len++] = '#';
1073 /* append the UID */
1074 AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1075 uid.bv_val, uid.bv_len );
1076 normalized->bv_len += uid.bv_len;
1079 normalized->bv_val[normalized->bv_len] = '\0';
1082 slap_sl_free( out.bv_val, ctx );
1085 return LDAP_SUCCESS;
1094 struct berval *value,
1095 void *assertedValue )
1098 struct berval *asserted = (struct berval *) assertedValue;
1099 struct berval assertedDN = *asserted;
1100 struct berval assertedUID = BER_BVNULL;
1101 struct berval valueDN = *value;
1102 struct berval valueUID = BER_BVNULL;
1103 int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1105 if ( !BER_BVISEMPTY( asserted ) ) {
1106 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1107 if ( !BER_BVISNULL( &assertedUID ) ) {
1108 assertedUID.bv_val++;
1109 assertedUID.bv_len = assertedDN.bv_len
1110 - ( assertedUID.bv_val - assertedDN.bv_val );
1112 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1113 assertedDN.bv_len -= assertedUID.bv_len + 1;
1116 BER_BVZERO( &assertedUID );
1121 if ( !BER_BVISEMPTY( value ) ) {
1123 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1124 if ( !BER_BVISNULL( &valueUID ) ) {
1126 valueUID.bv_len = valueDN.bv_len
1127 - ( valueUID.bv_val - valueDN.bv_val );
1129 if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1130 valueDN.bv_len -= valueUID.bv_len + 1;
1133 BER_BVZERO( &valueUID );
1138 if( valueUID.bv_len && assertedUID.bv_len ) {
1139 match = valueUID.bv_len - assertedUID.bv_len;
1142 return LDAP_SUCCESS;
1145 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1148 return LDAP_SUCCESS;
1151 } else if ( !approx && valueUID.bv_len ) {
1154 return LDAP_SUCCESS;
1156 } else if ( !approx && assertedUID.bv_len ) {
1159 return LDAP_SUCCESS;
1162 return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1166 uniqueMemberIndexer(
1171 struct berval *prefix,
1179 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1180 /* just count them */
1184 dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1186 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1187 struct berval assertedDN = values[i];
1188 struct berval assertedUID = BER_BVNULL;
1190 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1191 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1192 if ( !BER_BVISNULL( &assertedUID ) ) {
1193 assertedUID.bv_val++;
1194 assertedUID.bv_len = assertedDN.bv_len
1195 - ( assertedUID.bv_val - assertedDN.bv_val );
1197 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1198 assertedDN.bv_len -= assertedUID.bv_len + 1;
1201 BER_BVZERO( &assertedUID );
1206 dnvalues[i] = assertedDN;
1208 BER_BVZERO( &dnvalues[i] );
1210 rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1211 dnvalues, keysp, ctx );
1213 slap_sl_free( dnvalues, ctx );
1223 struct berval *prefix,
1224 void * assertedValue,
1228 struct berval *asserted = (struct berval *) assertedValue;
1229 struct berval assertedDN = *asserted;
1230 struct berval assertedUID = BER_BVNULL;
1232 if ( !BER_BVISEMPTY( asserted ) ) {
1233 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1234 if ( !BER_BVISNULL( &assertedUID ) ) {
1235 assertedUID.bv_val++;
1236 assertedUID.bv_len = assertedDN.bv_len
1237 - ( assertedUID.bv_val - assertedDN.bv_val );
1239 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1240 assertedDN.bv_len -= assertedUID.bv_len + 1;
1243 BER_BVZERO( &assertedUID );
1248 return octetStringFilter( use, flags, syntax, mr, prefix,
1249 &assertedDN, keysp, ctx );
1254 * Handling boolean syntax and matching is quite rigid.
1255 * A more flexible approach would be to allow a variety
1256 * of strings to be normalized and prettied into TRUE
1264 /* very unforgiving validation, requires no normalization
1265 * before simplistic matching
1268 if( in->bv_len == 4 ) {
1269 if( bvmatch( in, &slap_true_bv ) ) {
1270 return LDAP_SUCCESS;
1272 } else if( in->bv_len == 5 ) {
1273 if( bvmatch( in, &slap_false_bv ) ) {
1274 return LDAP_SUCCESS;
1278 return LDAP_INVALID_SYNTAX;
1287 struct berval *value,
1288 void *assertedValue )
1290 /* simplistic matching allowed by rigid validation */
1291 struct berval *asserted = (struct berval *) assertedValue;
1292 *matchp = value->bv_len != asserted->bv_len;
1293 return LDAP_SUCCESS;
1296 /*-------------------------------------------------------------------
1297 LDAP/X.500 string syntax / matching rules have a few oddities. This
1298 comment attempts to detail how slapd(8) treats them.
1301 StringSyntax X.500 LDAP Matching/Comments
1302 DirectoryString CHOICE UTF8 i/e + ignore insignificant spaces
1303 PrintableString subset subset i/e + ignore insignificant spaces
1304 PrintableString subset subset i/e + ignore insignificant spaces
1305 NumericString subset subset ignore all spaces
1306 IA5String ASCII ASCII i/e + ignore insignificant spaces
1307 TeletexString T.61 T.61 i/e + ignore insignificant spaces
1309 TelephoneNumber subset subset i + ignore all spaces and "-"
1311 See RFC 4518 for details.
1315 In X.500(93), a directory string can be either a PrintableString,
1316 a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1317 In later versions, more CHOICEs were added. In all cases the string
1320 In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1321 A directory string cannot be zero length.
1323 For matching, there are both case ignore and exact rules. Both
1324 also require that "insignificant" spaces be ignored.
1325 spaces before the first non-space are ignored;
1326 spaces after the last non-space are ignored;
1327 spaces after a space are ignored.
1328 Note: by these rules (and as clarified in X.520), a string of only
1329 spaces is to be treated as if held one space, not empty (which
1330 would be a syntax error).
1333 In ASN.1, numeric string is just a string of digits and spaces
1334 and could be empty. However, in X.500, all attribute values of
1335 numeric string carry a non-empty constraint. For example:
1337 internationalISDNNumber ATTRIBUTE ::= {
1338 WITH SYNTAX InternationalISDNNumber
1339 EQUALITY MATCHING RULE numericStringMatch
1340 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1341 ID id-at-internationalISDNNumber }
1342 InternationalISDNNumber ::=
1343 NumericString (SIZE(1..ub-international-isdn-number))
1345 Unforunately, some assertion values are don't carry the same
1346 constraint (but its unclear how such an assertion could ever
1347 be true). In LDAP, there is one syntax (numericString) not two
1348 (numericString with constraint, numericString without constraint).
1349 This should be treated as numericString with non-empty constraint.
1350 Note that while someone may have no ISDN number, there are no ISDN
1351 numbers which are zero length.
1353 In matching, spaces are ignored.
1356 In ASN.1, Printable string is just a string of printable characters
1357 and can be empty. In X.500, semantics much like NumericString (see
1358 serialNumber for a like example) excepting uses insignificant space
1359 handling instead of ignore all spaces.
1362 Basically same as PrintableString. There are no examples in X.500,
1363 but same logic applies. So we require them to be non-empty as
1366 -------------------------------------------------------------------*/
1375 unsigned char *u = (unsigned char *)in->bv_val;
1377 if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1378 /* directory strings cannot be empty */
1379 return LDAP_INVALID_SYNTAX;
1382 for( count = in->bv_len; count > 0; count -= len, u += len ) {
1383 /* get the length indicated by the first byte */
1384 len = LDAP_UTF8_CHARLEN2( u, len );
1386 /* very basic checks */
1389 if( (u[5] & 0xC0) != 0x80 ) {
1390 return LDAP_INVALID_SYNTAX;
1393 if( (u[4] & 0xC0) != 0x80 ) {
1394 return LDAP_INVALID_SYNTAX;
1397 if( (u[3] & 0xC0) != 0x80 ) {
1398 return LDAP_INVALID_SYNTAX;
1401 if( (u[2] & 0xC0 )!= 0x80 ) {
1402 return LDAP_INVALID_SYNTAX;
1405 if( (u[1] & 0xC0) != 0x80 ) {
1406 return LDAP_INVALID_SYNTAX;
1409 /* CHARLEN already validated it */
1412 return LDAP_INVALID_SYNTAX;
1415 /* make sure len corresponds with the offset
1416 to the next character */
1417 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1421 return LDAP_INVALID_SYNTAX;
1424 return LDAP_SUCCESS;
1428 UTF8StringNormalize(
1433 struct berval *normalized,
1436 struct berval tmp, nvalue;
1440 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
1442 if( BER_BVISNULL( val ) ) {
1443 /* assume we're dealing with a syntax (e.g., UTF8String)
1444 * which allows empty strings
1446 BER_BVZERO( normalized );
1447 return LDAP_SUCCESS;
1450 flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1451 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1452 flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1453 ? LDAP_UTF8_APPROX : 0;
1455 val = UTF8bvnormalize( val, &tmp, flags, ctx );
1460 /* collapse spaces (in place) */
1462 nvalue.bv_val = tmp.bv_val;
1464 /* trim leading spaces? */
1465 wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1466 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1468 for( i = 0; i < tmp.bv_len; i++) {
1469 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1470 if( wasspace++ == 0 ) {
1471 /* trim repeated spaces */
1472 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1476 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1480 if( !BER_BVISEMPTY( &nvalue ) ) {
1481 /* trim trailing space? */
1483 (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1484 ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1488 nvalue.bv_val[nvalue.bv_len] = '\0';
1491 /* string of all spaces is treated as one space */
1492 nvalue.bv_val[0] = ' ';
1493 nvalue.bv_val[1] = '\0';
1497 *normalized = nvalue;
1498 return LDAP_SUCCESS;
1502 directoryStringSubstringsMatch(
1507 struct berval *value,
1508 void *assertedValue )
1511 SubstringsAssertion *sub = assertedValue;
1512 struct berval left = *value;
1516 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1517 if ( sub->sa_initial.bv_len > left.bv_len ) {
1518 /* not enough left */
1523 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1524 sub->sa_initial.bv_len );
1530 left.bv_val += sub->sa_initial.bv_len;
1531 left.bv_len -= sub->sa_initial.bv_len;
1533 priorspace = ASCII_SPACE(
1534 sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1537 if ( sub->sa_any ) {
1538 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1542 if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] )
1543 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1545 /* allow next space to match */
1552 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1556 if ( sub->sa_any[i].bv_len > left.bv_len ) {
1557 /* not enough left */
1562 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1569 idx = p - left.bv_val;
1571 if ( idx >= left.bv_len ) {
1572 /* this shouldn't happen */
1579 if ( sub->sa_any[i].bv_len > left.bv_len ) {
1580 /* not enough left */
1585 match = memcmp( left.bv_val,
1586 sub->sa_any[i].bv_val,
1587 sub->sa_any[i].bv_len );
1595 left.bv_val += sub->sa_any[i].bv_len;
1596 left.bv_len -= sub->sa_any[i].bv_len;
1598 priorspace = ASCII_SPACE(
1599 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1603 if ( !BER_BVISNULL( &sub->sa_final ) ) {
1604 if( priorspace && !BER_BVISEMPTY( &sub->sa_final )
1605 && ASCII_SPACE( sub->sa_final.bv_val[0] ))
1607 /* allow next space to match */
1612 if ( sub->sa_final.bv_len > left.bv_len ) {
1613 /* not enough left */
1618 match = memcmp( sub->sa_final.bv_val,
1619 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1620 sub->sa_final.bv_len );
1629 return LDAP_SUCCESS;
1632 #if defined(SLAPD_APPROX_INITIALS)
1633 # define SLAPD_APPROX_DELIMITER "._ "
1634 # define SLAPD_APPROX_WORDLEN 2
1636 # define SLAPD_APPROX_DELIMITER " "
1637 # define SLAPD_APPROX_WORDLEN 1
1646 struct berval *value,
1647 void *assertedValue )
1649 struct berval *nval, *assertv;
1650 char *val, **values, **words, *c;
1651 int i, count, len, nextchunk=0, nextavail=0;
1653 /* Yes, this is necessary */
1654 nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
1655 if( nval == NULL ) {
1657 return LDAP_SUCCESS;
1660 /* Yes, this is necessary */
1661 assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1662 NULL, LDAP_UTF8_APPROX, NULL );
1663 if( assertv == NULL ) {
1666 return LDAP_SUCCESS;
1669 /* Isolate how many words there are */
1670 for ( c = nval->bv_val, count = 1; *c; c++ ) {
1671 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1672 if ( c == NULL ) break;
1677 /* Get a phonetic copy of each word */
1678 words = (char **)ch_malloc( count * sizeof(char *) );
1679 values = (char **)ch_malloc( count * sizeof(char *) );
1680 for ( c = nval->bv_val, i = 0; i < count; i++, c += strlen(c) + 1 ) {
1682 values[i] = phonetic(c);
1685 /* Work through the asserted value's words, to see if at least some
1686 of the words are there, in the same order. */
1688 while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1689 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1694 #if defined(SLAPD_APPROX_INITIALS)
1695 else if( len == 1 ) {
1696 /* Single letter words need to at least match one word's initial */
1697 for( i=nextavail; i<count; i++ )
1698 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1705 /* Isolate the next word in the asserted value and phonetic it */
1706 assertv->bv_val[nextchunk+len] = '\0';
1707 val = phonetic( assertv->bv_val + nextchunk );
1709 /* See if this phonetic chunk is in the remaining words of *value */
1710 for( i=nextavail; i<count; i++ ){
1711 if( !strcmp( val, values[i] ) ){
1719 /* This chunk in the asserted value was NOT within the *value. */
1725 /* Go on to the next word in the asserted value */
1729 /* If some of the words were seen, call it a match */
1730 if( nextavail > 0 ) {
1737 /* Cleanup allocs */
1738 ber_bvfree( assertv );
1739 for( i=0; i<count; i++ ) {
1740 ch_free( values[i] );
1746 return LDAP_SUCCESS;
1755 struct berval *prefix,
1761 int i,j, len, wordcount, keycount=0;
1762 struct berval *newkeys;
1763 BerVarray keys=NULL;
1765 for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
1766 struct berval val = BER_BVNULL;
1767 /* Yes, this is necessary */
1768 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
1769 assert( !BER_BVISNULL( &val ) );
1771 /* Isolate how many words there are. There will be a key for each */
1772 for( wordcount = 0, c = val.bv_val; *c; c++) {
1773 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1774 if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1776 if (*c == '\0') break;
1780 /* Allocate/increase storage to account for new keys */
1781 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1)
1782 * sizeof(struct berval) );
1783 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1784 if( keys ) ch_free( keys );
1787 /* Get a phonetic copy of each word */
1788 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1790 if( len < SLAPD_APPROX_WORDLEN ) continue;
1791 ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1796 ber_memfree( val.bv_val );
1798 BER_BVZERO( &keys[keycount] );
1801 return LDAP_SUCCESS;
1810 struct berval *prefix,
1811 void * assertedValue,
1820 /* Yes, this is necessary */
1821 val = UTF8bvnormalize( ((struct berval *)assertedValue),
1822 NULL, LDAP_UTF8_APPROX, NULL );
1823 if( val == NULL || BER_BVISNULL( val ) ) {
1824 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1825 BER_BVZERO( &keys[0] );
1828 return LDAP_SUCCESS;
1831 /* Isolate how many words there are. There will be a key for each */
1832 for( count = 0,c = val->bv_val; *c; c++) {
1833 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1834 if( len >= SLAPD_APPROX_WORDLEN ) count++;
1836 if (*c == '\0') break;
1840 /* Allocate storage for new keys */
1841 keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1843 /* Get a phonetic copy of each word */
1844 for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1846 if( len < SLAPD_APPROX_WORDLEN ) continue;
1847 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1853 BER_BVZERO( &keys[count] );
1856 return LDAP_SUCCESS;
1859 /* Remove all spaces and '-' characters */
1861 telephoneNumberNormalize(
1866 struct berval *normalized,
1871 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1873 /* validator should have refused an empty string */
1874 assert( !BER_BVISEMPTY( val ) );
1876 q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
1878 for( p = val->bv_val; *p; p++ ) {
1879 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1885 normalized->bv_len = q - normalized->bv_val;
1887 if( BER_BVISEMPTY( normalized ) ) {
1888 slap_sl_free( normalized->bv_val, ctx );
1889 BER_BVZERO( normalized );
1890 return LDAP_INVALID_SYNTAX;
1893 return LDAP_SUCCESS;
1901 struct berval val = *in;
1903 if( BER_BVISEMPTY( &val ) ) {
1904 /* disallow empty strings */
1905 return LDAP_INVALID_SYNTAX;
1908 while( OID_LEADCHAR( val.bv_val[0] ) ) {
1909 if ( val.bv_len == 1 ) {
1910 return LDAP_SUCCESS;
1913 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
1920 while ( OID_LEADCHAR( val.bv_val[0] )) {
1924 if ( val.bv_len == 0 ) {
1925 return LDAP_SUCCESS;
1929 if( !OID_SEPARATOR( val.bv_val[0] )) {
1937 return LDAP_INVALID_SYNTAX;
1946 struct berval val = *in;
1948 if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
1950 if ( val.bv_val[0] == '-' ) {
1954 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
1955 return LDAP_INVALID_SYNTAX;
1958 if( val.bv_val[0] == '0' ) { /* "-0" */
1959 return LDAP_INVALID_SYNTAX;
1962 } else if ( val.bv_val[0] == '0' ) {
1963 if( val.bv_len > 1 ) { /* "0<more>" */
1964 return LDAP_INVALID_SYNTAX;
1967 return LDAP_SUCCESS;
1970 for( i=0; i < val.bv_len; i++ ) {
1971 if( !ASCII_DIGIT(val.bv_val[i]) ) {
1972 return LDAP_INVALID_SYNTAX;
1976 return LDAP_SUCCESS;
1985 struct berval *value,
1986 void *assertedValue )
1988 struct berval *asserted = (struct berval *) assertedValue;
1989 int vsign = 1, asign = 1; /* default sign = '+' */
1994 if( v.bv_val[0] == '-' ) {
2000 if( BER_BVISEMPTY( &v ) ) vsign = 0;
2003 if( a.bv_val[0] == '-' ) {
2009 if( BER_BVISEMPTY( &a ) ) vsign = 0;
2011 match = vsign - asign;
2013 match = ( v.bv_len != a.bv_len
2014 ? ( v.bv_len < a.bv_len ? -1 : 1 )
2015 : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2016 if( vsign < 0 ) match = -match;
2020 return LDAP_SUCCESS;
2024 countryStringValidate(
2026 struct berval *val )
2028 if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2030 if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2031 return LDAP_INVALID_SYNTAX;
2033 if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2034 return LDAP_INVALID_SYNTAX;
2037 return LDAP_SUCCESS;
2041 printableStringValidate(
2043 struct berval *val )
2047 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2049 for(i=0; i < val->bv_len; i++) {
2050 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2051 return LDAP_INVALID_SYNTAX;
2055 return LDAP_SUCCESS;
2059 printablesStringValidate(
2061 struct berval *val )
2065 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2067 for(i=0,len=0; i < val->bv_len; i++) {
2068 int c = val->bv_val[i];
2072 return LDAP_INVALID_SYNTAX;
2076 } else if ( SLAP_PRINTABLE(c) ) {
2079 return LDAP_INVALID_SYNTAX;
2084 return LDAP_INVALID_SYNTAX;
2087 return LDAP_SUCCESS;
2093 struct berval *val )
2097 for(i=0; i < val->bv_len; i++) {
2098 if( !LDAP_ASCII(val->bv_val[i]) ) {
2099 return LDAP_INVALID_SYNTAX;
2103 return LDAP_SUCCESS;
2112 struct berval *normalized,
2116 int casefold = !SLAP_MR_ASSOCIATED( mr,
2117 slap_schema.si_mr_caseExactIA5Match );
2119 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2123 /* Ignore initial whitespace */
2124 while ( ASCII_SPACE( *p ) ) p++;
2126 normalized->bv_len = val->bv_len - ( p - val->bv_val );
2127 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2128 AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2129 normalized->bv_val[normalized->bv_len] = '\0';
2131 p = q = normalized->bv_val;
2134 if ( ASCII_SPACE( *p ) ) {
2137 /* Ignore the extra whitespace */
2138 while ( ASCII_SPACE( *p ) ) {
2142 } else if ( casefold ) {
2143 /* Most IA5 rules require casefolding */
2144 *q++ = TOLOWER(*p); p++;
2151 assert( normalized->bv_val <= p );
2155 * If the string ended in space, backup the pointer one
2156 * position. One is enough because the above loop collapsed
2157 * all whitespace to a single space.
2159 if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2161 /* null terminate */
2164 normalized->bv_len = q - normalized->bv_val;
2166 return LDAP_SUCCESS;
2175 if( in->bv_len != 36 ) {
2176 return LDAP_INVALID_SYNTAX;
2179 for( i=0; i<36; i++ ) {
2185 if( in->bv_val[i] != '-' ) {
2186 return LDAP_INVALID_SYNTAX;
2190 if( !ASCII_HEX( in->bv_val[i]) ) {
2191 return LDAP_INVALID_SYNTAX;
2196 return LDAP_SUCCESS;
2207 int rc=LDAP_INVALID_SYNTAX;
2209 assert( in != NULL );
2210 assert( out != NULL );
2212 if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2215 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2217 for( i=0; i<36; i++ ) {
2223 if( in->bv_val[i] != '-' ) {
2226 out->bv_val[i] = '-';
2230 if( !ASCII_HEX( in->bv_val[i]) ) {
2233 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2238 out->bv_val[ out->bv_len ] = '\0';
2242 slap_sl_free( out->bv_val, ctx );
2255 struct berval *normalized,
2258 unsigned char octet = '\0';
2261 normalized->bv_len = 16;
2262 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2264 for( i=0, j=0; i<36; i++ ) {
2265 unsigned char nibble;
2266 if( val->bv_val[i] == '-' ) {
2269 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2270 nibble = val->bv_val[i] - '0';
2272 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2273 nibble = val->bv_val[i] - ('a'-10);
2275 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2276 nibble = val->bv_val[i] - ('A'-10);
2279 slap_sl_free( normalized->bv_val, ctx );
2280 return LDAP_INVALID_SYNTAX;
2285 normalized->bv_val[j>>1] = octet;
2287 octet = nibble << 4;
2292 normalized->bv_val[normalized->bv_len] = 0;
2293 return LDAP_SUCCESS;
2299 numericStringValidate(
2305 if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2307 for(i=0; i < in->bv_len; i++) {
2308 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2309 return LDAP_INVALID_SYNTAX;
2313 return LDAP_SUCCESS;
2317 numericStringNormalize(
2322 struct berval *normalized,
2325 /* removal all spaces */
2328 assert( !BER_BVISEMPTY( val ) );
2330 normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2333 q = normalized->bv_val;
2336 if ( ASCII_SPACE( *p ) ) {
2337 /* Ignore whitespace */
2344 /* we should have copied no more then is in val */
2345 assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2347 /* null terminate */
2350 normalized->bv_len = q - normalized->bv_val;
2352 if( BER_BVISEMPTY( normalized ) ) {
2353 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2354 normalized->bv_val[0] = ' ';
2355 normalized->bv_val[1] = '\0';
2356 normalized->bv_len = 1;
2359 return LDAP_SUCCESS;
2363 * Integer conversion macros that will use the largest available
2366 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
2367 # define SLAP_STRTOL(n,e,b) strtoll(n,e,b)
2368 # define SLAP_LONG long long
2370 # define SLAP_STRTOL(n,e,b) strtol(n,e,b)
2371 # define SLAP_LONG long
2372 #endif /* HAVE_STRTOLL ... */
2380 struct berval *value,
2381 void *assertedValue )
2383 SLAP_LONG lValue, lAssertedValue;
2386 /* safe to assume integers are NUL terminated? */
2387 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2388 if( errno == ERANGE )
2390 return LDAP_CONSTRAINT_VIOLATION;
2393 lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2395 if( errno == ERANGE )
2397 return LDAP_CONSTRAINT_VIOLATION;
2400 *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2401 return LDAP_SUCCESS;
2410 struct berval *value,
2411 void *assertedValue )
2413 SLAP_LONG lValue, lAssertedValue;
2416 /* safe to assume integers are NUL terminated? */
2417 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2418 if( errno == ERANGE )
2420 return LDAP_CONSTRAINT_VIOLATION;
2423 lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2425 if( errno == ERANGE )
2427 return LDAP_CONSTRAINT_VIOLATION;
2430 *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2431 return LDAP_SUCCESS;
2435 serialNumberAndIssuerValidate(
2441 struct berval sn, i;
2443 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
2446 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2448 if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2449 /* Parse old format */
2450 i.bv_val = ber_bvchr( in, '$' );
2451 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2453 sn.bv_val = in->bv_val;
2454 sn.bv_len = i.bv_val - in->bv_val;
2457 i.bv_len = in->bv_len - (sn.bv_len + 1);
2459 /* eat leading zeros */
2460 for( n=0; n < (sn.bv_len-1); n++ ) {
2461 if( sn.bv_val[n] != '0' ) break;
2466 for( n=0; n < sn.bv_len; n++ ) {
2467 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2471 /* Parse GSER format */
2472 int havesn=0,haveissuer=0;
2473 struct berval x = *in;
2477 /* eat leading spaces */
2478 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2482 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2483 return LDAP_INVALID_SYNTAX;
2486 /* should be at issuer or serialNumber NamedValue */
2487 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2489 x.bv_val += STRLENOF("issuer");
2490 x.bv_len -= STRLENOF("issuer");
2492 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2493 x.bv_val++; x.bv_len--;
2495 /* eat leading spaces */
2496 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2500 if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2501 x.bv_val++; x.bv_len--;
2503 i.bv_val = x.bv_val;
2506 for( ; i.bv_len < x.bv_len; ) {
2507 if ( i.bv_val[i.bv_len] != '"' ) {
2511 if ( i.bv_val[i.bv_len+1] == '"' ) {
2518 x.bv_val += i.bv_len+1;
2519 x.bv_len -= i.bv_len+1;
2521 if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2522 return LDAP_INVALID_SYNTAX;
2527 } else if( strncasecmp( x.bv_val, "serialNumber",
2528 STRLENOF("serialNumber")) == 0 )
2530 /* parse serialNumber */
2532 x.bv_val += STRLENOF("serialNumber");
2533 x.bv_len -= STRLENOF("serialNumber");
2535 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2536 x.bv_val++; x.bv_len--;
2538 /* eat leading spaces */
2539 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2543 sn.bv_val = x.bv_val;
2546 if( sn.bv_val[0] == '-' ) {
2551 for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2552 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2555 if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2556 if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2557 return LDAP_INVALID_SYNTAX;
2560 x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
2562 if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2563 return LDAP_INVALID_SYNTAX;
2568 } else return LDAP_INVALID_SYNTAX;
2570 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2571 x.bv_val++; x.bv_len--;
2574 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2578 /* should be at remaining NamedValue */
2579 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2580 STRLENOF("issuer" )) == 0 ))
2583 x.bv_val += STRLENOF("issuer");
2584 x.bv_len -= STRLENOF("issuer");
2586 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2587 x.bv_val++; x.bv_len--;
2589 /* eat leading spaces */
2590 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2594 if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2595 x.bv_val++; x.bv_len--;
2597 i.bv_val = x.bv_val;
2600 for( ; i.bv_len < x.bv_len; ) {
2601 if ( i.bv_val[i.bv_len] != '"' ) {
2605 if ( i.bv_val[i.bv_len+1] == '"' ) {
2612 x.bv_val += i.bv_len+1;
2613 x.bv_len -= i.bv_len+1;
2615 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2616 STRLENOF("serialNumber")) == 0 ))
2618 /* parse serialNumber */
2620 x.bv_val += STRLENOF("serialNumber");
2621 x.bv_len -= STRLENOF("serialNumber");
2623 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2624 x.bv_val++; x.bv_len--;
2626 /* eat leading spaces */
2627 for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2631 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2632 x.bv_val++; x.bv_len--;
2634 sn.bv_val = x.bv_val;
2637 if( sn.bv_val[0] == '-' ) {
2642 for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2643 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2646 if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2647 if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2648 return LDAP_INVALID_SYNTAX;
2651 x.bv_val += sn.bv_len;
2652 x.bv_len -= sn.bv_len;
2654 } else return LDAP_INVALID_SYNTAX;
2656 /* eat trailing spaces */
2657 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2661 /* should have no characters left... */
2662 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
2665 /* validate DN -- doesn't handle double dquote */
2666 rc = dnValidate( NULL, &i );
2667 if( rc ) return LDAP_INVALID_SYNTAX;
2669 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: OKAY\n",
2671 return LDAP_SUCCESS;
2675 serialNumberAndIssuerPretty(
2683 struct berval sn, i, ni;
2685 assert( in != NULL );
2686 assert( out != NULL );
2688 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
2691 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2693 if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2694 /* Parse old format */
2695 i.bv_val = ber_bvchr( in, '$' );
2696 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2698 sn.bv_val = in->bv_val;
2699 sn.bv_len = i.bv_val - in->bv_val;
2702 i.bv_len = in->bv_len - (sn.bv_len + 1);
2704 /* eat leading zeros */
2705 for( n=0; n < (sn.bv_len-1); n++ ) {
2706 if( sn.bv_val[n] != '0' ) break;
2711 for( n=0; n < sn.bv_len; n++ ) {
2712 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2716 /* Parse GSER format */
2717 int havesn=0,haveissuer=0;
2718 struct berval x = *in;
2722 /* eat leading spaces */
2723 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2727 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2728 return LDAP_INVALID_SYNTAX;
2731 /* should be at issuer or serialNumber NamedValue */
2732 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2734 x.bv_val += STRLENOF("issuer");
2735 x.bv_len -= STRLENOF("issuer");
2737 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2738 x.bv_val++; x.bv_len--;
2740 /* eat leading spaces */
2741 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2745 if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2746 x.bv_val++; x.bv_len--;
2748 i.bv_val = x.bv_val;
2751 for( ; i.bv_len < x.bv_len; ) {
2752 if ( i.bv_val[i.bv_len] != '"' ) {
2756 if ( i.bv_val[i.bv_len+1] == '"' ) {
2763 x.bv_val += i.bv_len+1;
2764 x.bv_len -= i.bv_len+1;
2766 if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2767 return LDAP_INVALID_SYNTAX;
2772 } else if( strncasecmp( x.bv_val, "serialNumber",
2773 STRLENOF("serialNumber")) == 0 )
2775 /* parse serialNumber */
2777 x.bv_val += STRLENOF("serialNumber");
2778 x.bv_len -= STRLENOF("serialNumber");
2780 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2781 x.bv_val++; x.bv_len--;
2783 /* eat leading spaces */
2784 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2788 sn.bv_val = x.bv_val;
2791 if( sn.bv_val[0] == '-' ) {
2796 for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2797 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2800 if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2801 if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2802 return LDAP_INVALID_SYNTAX;
2805 x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
2807 if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2808 return LDAP_INVALID_SYNTAX;
2813 } else return LDAP_INVALID_SYNTAX;
2815 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2816 x.bv_val++; x.bv_len--;
2819 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2823 /* should be at remaining NamedValue */
2824 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2825 STRLENOF("issuer" )) == 0 ))
2828 x.bv_val += STRLENOF("issuer");
2829 x.bv_len -= STRLENOF("issuer");
2831 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2832 x.bv_val++; x.bv_len--;
2834 /* eat leading spaces */
2835 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2839 if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2840 x.bv_val++; x.bv_len--;
2842 i.bv_val = x.bv_val;
2845 for( ; i.bv_len < x.bv_len; ) {
2846 if ( i.bv_val[i.bv_len] != '"' ) {
2850 if ( i.bv_val[i.bv_len+1] == '"' ) {
2857 x.bv_val += i.bv_len+1;
2858 x.bv_len -= i.bv_len+1;
2860 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2861 STRLENOF("serialNumber")) == 0 ))
2863 /* parse serialNumber */
2865 x.bv_val += STRLENOF("serialNumber");
2866 x.bv_len -= STRLENOF("serialNumber");
2868 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2869 x.bv_val++; x.bv_len--;
2871 /* eat leading spaces */
2872 for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2876 sn.bv_val = x.bv_val;
2879 if( sn.bv_val[0] == '-' ) {
2884 for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
2885 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
2888 if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
2889 if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
2890 return LDAP_INVALID_SYNTAX;
2893 x.bv_val += sn.bv_len;
2894 x.bv_len -= sn.bv_len;
2896 } else return LDAP_INVALID_SYNTAX;
2898 /* eat trailing spaces */
2899 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2903 /* should have no characters left... */
2904 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
2906 ber_dupbv_x( &ni, &i, ctx );
2909 /* need to handle double dquotes here */
2912 rc = dnPretty( syntax, &i, &ni, ctx );
2914 if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
2915 slap_sl_free( i.bv_val, ctx );
2918 if( rc ) return LDAP_INVALID_SYNTAX;
2920 /* make room from sn + "$" */
2921 out->bv_len = STRLENOF("{ serialNumber , issuer \"\" }")
2922 + sn.bv_len + ni.bv_len;
2923 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2925 if( out->bv_val == NULL ) {
2927 slap_sl_free( ni.bv_val, ctx );
2932 AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
2933 STRLENOF("{ serialNumber "));
2934 n = STRLENOF("{ serialNumber ");
2936 AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
2939 AC_MEMCPY( &out->bv_val[n], ", issuer \"", STRLENOF(", issuer \""));
2940 n += STRLENOF(", issuer \"");
2942 AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
2945 AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF("\" }"));
2946 n += STRLENOF("\" }");
2948 out->bv_val[n] = '\0';
2950 assert( n == out->bv_len );
2952 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
2953 out->bv_val, 0, 0 );
2955 slap_sl_free( ni.bv_val, ctx );
2957 return LDAP_SUCCESS;
2961 * This routine is called by certificateExactNormalize when
2962 * certificateExactNormalize receives a search string instead of
2963 * a certificate. This routine checks if the search value is valid
2964 * and then returns the normalized value
2967 serialNumberAndIssuerNormalize(
2977 struct berval sn, i, ni;
2979 assert( in != NULL );
2980 assert( out != NULL );
2982 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
2985 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2987 if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2988 /* Parse old format */
2989 i.bv_val = ber_bvchr( in, '$' );
2990 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2992 sn.bv_val = in->bv_val;
2993 sn.bv_len = i.bv_val - in->bv_val;
2996 i.bv_len = in->bv_len - (sn.bv_len + 1);
2998 /* eat leading zeros */
2999 for( n=0; n < (sn.bv_len-1); n++ ) {
3000 if( sn.bv_val[n] != '0' ) break;
3005 for( n=0; n < sn.bv_len; n++ ) {
3006 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3010 /* Parse GSER format */
3011 int havesn=0,haveissuer=0;
3012 struct berval x = *in;
3016 /* eat leading spaces */
3017 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3021 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
3022 return LDAP_INVALID_SYNTAX;
3025 /* should be at issuer or serialNumber NamedValue */
3026 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
3028 x.bv_val += STRLENOF("issuer");
3029 x.bv_len -= STRLENOF("issuer");
3031 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3032 x.bv_val++; x.bv_len--;
3034 /* eat leading spaces */
3035 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3039 if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3040 x.bv_val++; x.bv_len--;
3042 i.bv_val = x.bv_val;
3045 for( ; i.bv_len < x.bv_len; ) {
3046 if ( i.bv_val[i.bv_len] != '"' ) {
3050 if ( i.bv_val[i.bv_len+1] == '"' ) {
3057 x.bv_val += i.bv_len+1;
3058 x.bv_len -= i.bv_len+1;
3060 if ( x.bv_len < STRLENOF(",serialNumber 0")) {
3061 return LDAP_INVALID_SYNTAX;
3066 } else if( strncasecmp( x.bv_val, "serialNumber",
3067 STRLENOF("serialNumber")) == 0 )
3069 /* parse serialNumber */
3071 x.bv_val += STRLENOF("serialNumber");
3072 x.bv_len -= STRLENOF("serialNumber");
3074 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3075 x.bv_val++; x.bv_len--;
3077 /* eat leading spaces */
3078 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3082 sn.bv_val = x.bv_val;
3085 if( sn.bv_val[0] == '-' ) {
3090 for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
3091 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
3094 if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
3095 if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
3096 return LDAP_INVALID_SYNTAX;
3099 x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
3101 if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
3102 return LDAP_INVALID_SYNTAX;
3107 } else return LDAP_INVALID_SYNTAX;
3109 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
3110 x.bv_val++; x.bv_len--;
3113 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3117 /* should be at remaining NamedValue */
3118 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
3119 STRLENOF("issuer" )) == 0 ))
3122 x.bv_val += STRLENOF("issuer");
3123 x.bv_len -= STRLENOF("issuer");
3125 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3126 x.bv_val++; x.bv_len--;
3128 /* eat leading spaces */
3129 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3133 if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3134 x.bv_val++; x.bv_len--;
3136 i.bv_val = x.bv_val;
3139 for( ; i.bv_len < x.bv_len; ) {
3140 if ( i.bv_val[i.bv_len] != '"' ) {
3144 if ( i.bv_val[i.bv_len+1] == '"' ) {
3151 x.bv_val += i.bv_len+1;
3152 x.bv_len -= i.bv_len+1;
3154 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
3155 STRLENOF("serialNumber")) == 0 ))
3157 /* parse serialNumber */
3159 x.bv_val += STRLENOF("serialNumber");
3160 x.bv_len -= STRLENOF("serialNumber");
3162 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3163 x.bv_val++; x.bv_len--;
3165 /* eat leading spaces */
3166 for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
3170 sn.bv_val = x.bv_val;
3173 if( sn.bv_val[0] == '-' ) {
3178 for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
3179 if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
3182 if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
3183 if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
3184 return LDAP_INVALID_SYNTAX;
3187 x.bv_val += sn.bv_len;
3188 x.bv_len -= sn.bv_len;
3190 } else return LDAP_INVALID_SYNTAX;
3192 /* eat trailing spaces */
3193 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3197 /* should have no characters left... */
3198 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
3200 ber_dupbv_x( &ni, &i, ctx );
3203 /* need to handle double dquotes here */
3206 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3208 if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3209 slap_sl_free( i.bv_val, ctx );
3212 if( rc ) return LDAP_INVALID_SYNTAX;
3214 /* make room from sn + "$" */
3215 out->bv_len = STRLENOF( "{ serialNumber , issuer \"\" }" )
3216 + sn.bv_len + ni.bv_len;
3217 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3219 if( out->bv_val == NULL ) {
3221 slap_sl_free( ni.bv_val, ctx );
3226 AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3227 STRLENOF( "{ serialNumber " ));
3228 n = STRLENOF( "{ serialNumber " );
3230 AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3233 AC_MEMCPY( &out->bv_val[n], ", issuer \"", STRLENOF( ", issuer \"" ));
3234 n += STRLENOF( ", issuer \"" );
3236 AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3239 AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF( "\" }" ));
3240 n += STRLENOF( "\" }" );
3242 out->bv_val[n] = '\0';
3244 assert( n == out->bv_len );
3246 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
3247 out->bv_val, 0, 0 );
3249 slap_sl_free( ni.bv_val, ctx );
3251 return LDAP_SUCCESS;
3255 certificateExactNormalize(
3260 struct berval *normalized,
3263 BerElementBuffer berbuf;
3264 BerElement *ber = (BerElement *)&berbuf;
3268 char serialbuf[64], *serial = serialbuf;
3269 ber_len_t seriallen;
3270 struct berval issuer_dn = BER_BVNULL, bvdn;
3272 int rc = LDAP_INVALID_SYNTAX;
3274 if( BER_BVISEMPTY( val ) ) goto done;
3276 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3277 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
3280 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3282 ber_init2( ber, val, LBER_USE_DER );
3283 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
3284 tag = ber_skip_tag( ber, &len ); /* Sequence */
3285 tag = ber_peek_tag( ber, &len ); /* Optional version? */
3286 if ( tag == 0xa0 ) {
3287 tag = ber_skip_tag( ber, &len );
3288 tag = ber_get_int( ber, &i ); /* version */
3291 /* NOTE: move the test here from certificateNormalize,
3292 * so that we can validate certs with serial longer
3293 * than sizeof(ber_int_t) */
3294 tag = ber_peek_tag( ber, &len ); /* serial */
3295 if ( len > sizeof(ber_int_t) ) {
3298 tag = ber_skip_tag( ber, &len );
3299 ptr = (unsigned char *)ber->ber_ptr;
3300 ber_skip_data( ber, len );
3302 while ( ptr[0] == '\0' && len > 0 ) {
3307 #if defined(USE_MP_BIGNUM)
3310 #elif defined(USE_MP_GMP)
3312 /* hint: use mpz_import(), mpz_get_str() */
3314 #elif defined(USE_MP_LONG_LONG)
3315 if ( len <= sizeof( unsigned long long ) ) {
3316 unsigned long long sn = 0;
3321 for ( i = 1; i < len; i++ ) {
3326 seriallen = snprintf( serialbuf, sizeof(serialbuf), "%llu", sn );
3329 rc = LDAP_INVALID_SYNTAX;
3334 tag = ber_get_int( ber, &i ); /* serial */
3335 seriallen = snprintf( serialbuf, sizeof(serialbuf), "%d", i );
3337 tag = ber_skip_tag( ber, &len ); /* SignatureAlg */
3338 ber_skip_data( ber, len );
3339 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
3340 len = ber_ptrlen( ber );
3341 bvdn.bv_val = val->bv_val + len;
3342 bvdn.bv_len = val->bv_len - len;
3344 rc = dnX509normalize( &bvdn, &issuer_dn );
3345 if( rc != LDAP_SUCCESS ) goto done;
3347 normalized->bv_len = STRLENOF( "{ serialNumber , issuer \"\" }" )
3348 + seriallen + issuer_dn.bv_len;
3349 normalized->bv_val = ch_malloc(normalized->bv_len+1);
3351 p = (unsigned char *)normalized->bv_val;
3353 AC_MEMCPY(p, "{ serialNumber ", STRLENOF( "{ serialNumber " ));
3354 p += STRLENOF( "{ serialNumber " );
3356 AC_MEMCPY(p, serial, seriallen);
3359 AC_MEMCPY(p, ", issuer \"", STRLENOF( ", issuer \"" ));
3360 p += STRLENOF( ", issuer \"" );
3362 AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
3363 p += issuer_dn.bv_len;
3365 AC_MEMCPY(p, "\" }", STRLENOF( "\" }" ));
3366 p += STRLENOF( "\" }" );
3370 Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
3371 normalized->bv_val, NULL, NULL );
3376 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3377 if ( serial != serialbuf ) ber_memfree_x( serial, ctx );
3383 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
3384 /* slight optimization - does not need the start parameter */
3385 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
3390 check_time_syntax (struct berval *val,
3393 struct berval *fraction)
3396 * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
3397 * start=1 UTCTime YYmmddHHMM[SS][Z|(+/-)HHMM]
3398 * GeneralizedTime supports leap seconds, UTCTime does not.
3400 static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
3401 static const int mdays[2][12] = {
3402 /* non-leap years */
3403 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
3405 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
3408 int part, c, c1, c2, tzoffset, leapyear = 0;
3411 e = p + val->bv_len;
3413 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3414 parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
3416 for (part = start; part < 7 && p < e; part++) {
3418 if (!ASCII_DIGIT(c1)) {
3423 return LDAP_INVALID_SYNTAX;
3426 if (!ASCII_DIGIT(c)) {
3427 return LDAP_INVALID_SYNTAX;
3429 c += c1 * 10 - '0' * 11;
3430 if ((part | 1) == 3) {
3433 return LDAP_INVALID_SYNTAX;
3436 if (c >= ceiling[part]) {
3437 if (! (c == 60 && part == 6 && start == 0))
3438 return LDAP_INVALID_SYNTAX;
3442 if (part < 5 + start) {
3443 return LDAP_INVALID_SYNTAX;
3445 for (; part < 9; part++) {
3449 /* leapyear check for the Gregorian calendar (year>1581) */
3450 if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
3454 if (parts[3] >= mdays[leapyear][parts[2]]) {
3455 return LDAP_INVALID_SYNTAX;
3459 fraction->bv_val = p;
3460 fraction->bv_len = 0;
3461 if (p < e && (*p == '.' || *p == ',')) {
3463 while (++p < e && ASCII_DIGIT(*p)) {
3466 if (p - fraction->bv_val == 1) {
3467 return LDAP_INVALID_SYNTAX;
3469 for (end_num = p; end_num[-1] == '0'; --end_num) {
3472 c = end_num - fraction->bv_val;
3473 if (c != 1) fraction->bv_len = c;
3479 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3485 return LDAP_INVALID_SYNTAX;
3491 for (part = 7; part < 9 && p < e; part++) {
3493 if (!ASCII_DIGIT(c1)) {
3498 return LDAP_INVALID_SYNTAX;
3501 if (!ASCII_DIGIT(c2)) {
3502 return LDAP_INVALID_SYNTAX;
3504 parts[part] = c1 * 10 + c2 - '0' * 11;
3505 if (parts[part] >= ceiling[part]) {
3506 return LDAP_INVALID_SYNTAX;
3509 if (part < 8 + start) {
3510 return LDAP_INVALID_SYNTAX;
3513 if (tzoffset == '-') {
3514 /* negative offset to UTC, ie west of Greenwich */
3515 parts[4] += parts[7];
3516 parts[5] += parts[8];
3517 /* offset is just hhmm, no seconds */
3518 for (part = 6; --part >= 0; ) {
3522 c = mdays[leapyear][parts[2]];
3524 if (parts[part] >= c) {
3526 return LDAP_INVALID_SYNTAX;
3531 } else if (part != 5) {
3536 /* positive offset to UTC, ie east of Greenwich */
3537 parts[4] -= parts[7];
3538 parts[5] -= parts[8];
3539 for (part = 6; --part >= 0; ) {
3540 if (parts[part] < 0) {
3542 return LDAP_INVALID_SYNTAX;
3547 /* make first arg to % non-negative */
3548 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
3553 } else if (part != 5) {
3560 return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
3563 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3570 struct berval *normalized )
3574 rc = check_time_syntax(val, 1, parts, NULL);
3575 if (rc != LDAP_SUCCESS) {
3579 normalized->bv_val = ch_malloc( 14 );
3580 if ( normalized->bv_val == NULL ) {
3581 return LBER_ERROR_MEMORY;
3584 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
3585 parts[1], parts[2] + 1, parts[3] + 1,
3586 parts[4], parts[5], parts[6] );
3587 normalized->bv_len = 13;
3589 return LDAP_SUCCESS;
3599 return check_time_syntax(in, 1, parts, NULL);
3602 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
3605 generalizedTimeValidate(
3610 struct berval fraction;
3611 return check_time_syntax(in, 0, parts, &fraction);
3615 generalizedTimeNormalize(
3620 struct berval *normalized,
3625 struct berval fraction;
3627 rc = check_time_syntax(val, 0, parts, &fraction);
3628 if (rc != LDAP_SUCCESS) {
3632 len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
3633 normalized->bv_val = slap_sl_malloc( len + 1, ctx );
3634 if ( BER_BVISNULL( normalized ) ) {
3635 return LBER_ERROR_MEMORY;
3638 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
3639 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
3640 parts[4], parts[5], parts[6] );
3641 if ( !BER_BVISEMPTY( &fraction ) ) {
3642 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
3643 fraction.bv_val, fraction.bv_len );
3644 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
3646 strcpy( normalized->bv_val + len-1, "Z" );
3647 normalized->bv_len = len;
3649 return LDAP_SUCCESS;
3653 generalizedTimeOrderingMatch(
3658 struct berval *value,
3659 void *assertedValue )
3661 struct berval *asserted = (struct berval *) assertedValue;
3662 ber_len_t v_len = value->bv_len;
3663 ber_len_t av_len = asserted->bv_len;
3665 /* ignore trailing 'Z' when comparing */
3666 int match = memcmp( value->bv_val, asserted->bv_val,
3667 (v_len < av_len ? v_len : av_len) - 1 );
3668 if ( match == 0 ) match = v_len - av_len;
3671 return LDAP_SUCCESS;
3674 /* Index generation function */
3675 int generalizedTimeIndexer(
3680 struct berval *prefix,
3688 BerValue bvtmp; /* 40 bit index */
3690 struct lutil_timet tt;
3692 bvtmp.bv_len = sizeof(tmp);
3694 for( i=0; values[i].bv_val != NULL; i++ ) {
3695 /* just count them */
3698 /* we should have at least one value at this point */
3701 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
3703 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
3704 for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
3705 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
3706 /* Use 40 bits of time for key */
3707 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
3708 lutil_tm2time( &tm, &tt );
3709 tmp[0] = tt.tt_gsec & 0xff;
3710 tmp[4] = tt.tt_sec & 0xff;
3712 tmp[3] = tt.tt_sec & 0xff;
3714 tmp[2] = tt.tt_sec & 0xff;
3716 tmp[1] = tt.tt_sec & 0xff;
3718 ber_dupbv_x(&keys[j++], &bvtmp, ctx );
3722 keys[j].bv_val = NULL;
3727 return LDAP_SUCCESS;
3730 /* Index generation function */
3731 int generalizedTimeFilter(
3736 struct berval *prefix,
3737 void * assertedValue,
3743 BerValue bvtmp; /* 40 bit index */
3744 BerValue *value = (BerValue *) assertedValue;
3746 struct lutil_timet tt;
3748 bvtmp.bv_len = sizeof(tmp);
3750 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
3751 /* Use 40 bits of time for key */
3752 if ( value->bv_val && value->bv_len >= 10 &&
3753 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
3755 lutil_tm2time( &tm, &tt );
3756 tmp[0] = tt.tt_gsec & 0xff;
3757 tmp[4] = tt.tt_sec & 0xff;
3759 tmp[3] = tt.tt_sec & 0xff;
3761 tmp[2] = tt.tt_sec & 0xff;
3763 tmp[1] = tt.tt_sec & 0xff;
3765 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
3766 ber_dupbv_x(keys, &bvtmp, ctx );
3767 keys[1].bv_val = NULL;
3775 return LDAP_SUCCESS;
3779 deliveryMethodValidate(
3781 struct berval *val )
3784 #define LENOF(s) (sizeof(s)-1)
3785 struct berval tmp = *val;
3787 * DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
3788 * pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
3789 * "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
3792 if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3794 switch( tmp.bv_val[0] ) {
3797 if(( tmp.bv_len >= LENOF("any") ) &&
3798 ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
3800 tmp.bv_len -= LENOF("any");
3801 tmp.bv_val += LENOF("any");
3804 return LDAP_INVALID_SYNTAX;
3808 if(( tmp.bv_len >= LENOF("mhs") ) &&
3809 ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
3811 tmp.bv_len -= LENOF("mhs");
3812 tmp.bv_val += LENOF("mhs");
3815 return LDAP_INVALID_SYNTAX;
3819 if(( tmp.bv_len >= LENOF("physical") ) &&
3820 ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
3822 tmp.bv_len -= LENOF("physical");
3823 tmp.bv_val += LENOF("physical");
3826 return LDAP_INVALID_SYNTAX;
3829 case 'T': /* telex or teletex or telephone */
3830 if(( tmp.bv_len >= LENOF("telex") ) &&
3831 ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
3833 tmp.bv_len -= LENOF("telex");
3834 tmp.bv_val += LENOF("telex");
3837 if(( tmp.bv_len >= LENOF("teletex") ) &&
3838 ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
3840 tmp.bv_len -= LENOF("teletex");
3841 tmp.bv_val += LENOF("teletex");
3844 if(( tmp.bv_len >= LENOF("telephone") ) &&
3845 ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
3847 tmp.bv_len -= LENOF("telephone");
3848 tmp.bv_val += LENOF("telephone");
3851 return LDAP_INVALID_SYNTAX;
3854 case 'G': /* g3fax or g4fax */
3855 if(( tmp.bv_len >= LENOF("g3fax") ) && (
3856 ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
3857 ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
3859 tmp.bv_len -= LENOF("g3fax");
3860 tmp.bv_val += LENOF("g3fax");
3863 return LDAP_INVALID_SYNTAX;
3867 if(( tmp.bv_len >= LENOF("ia5") ) &&
3868 ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
3870 tmp.bv_len -= LENOF("ia5");
3871 tmp.bv_val += LENOF("ia5");
3874 return LDAP_INVALID_SYNTAX;
3878 if(( tmp.bv_len >= LENOF("videotex") ) &&
3879 ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
3881 tmp.bv_len -= LENOF("videotex");
3882 tmp.bv_val += LENOF("videotex");
3885 return LDAP_INVALID_SYNTAX;
3888 return LDAP_INVALID_SYNTAX;
3891 if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
3893 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3897 if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
3901 return LDAP_INVALID_SYNTAX;
3903 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3912 nisNetgroupTripleValidate(
3914 struct berval *val )
3919 if ( BER_BVISEMPTY( val ) ) {
3920 return LDAP_INVALID_SYNTAX;
3923 p = (char *)val->bv_val;
3924 e = p + val->bv_len;
3926 if ( *p != '(' /*')'*/ ) {
3927 return LDAP_INVALID_SYNTAX;
3930 for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
3934 return LDAP_INVALID_SYNTAX;
3937 } else if ( !AD_CHAR( *p ) ) {
3938 return LDAP_INVALID_SYNTAX;
3942 if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
3943 return LDAP_INVALID_SYNTAX;
3949 return LDAP_INVALID_SYNTAX;
3952 return LDAP_SUCCESS;
3956 bootParameterValidate(
3958 struct berval *val )
3962 if ( BER_BVISEMPTY( val ) ) {
3963 return LDAP_INVALID_SYNTAX;
3966 p = (char *)val->bv_val;
3967 e = p + val->bv_len;
3970 for (; ( p < e ) && ( *p != '=' ); p++ ) {
3971 if ( !AD_CHAR( *p ) ) {
3972 return LDAP_INVALID_SYNTAX;
3977 return LDAP_INVALID_SYNTAX;
3981 for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
3982 if ( !AD_CHAR( *p ) ) {
3983 return LDAP_INVALID_SYNTAX;
3988 return LDAP_INVALID_SYNTAX;
3992 for ( p++; p < e; p++ ) {
3993 if ( !SLAP_PRINTABLE( *p ) ) {
3994 return LDAP_INVALID_SYNTAX;
3998 return LDAP_SUCCESS;
4002 firstComponentNormalize(
4007 struct berval *normalized,
4014 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
4015 ber_dupbv_x( normalized, val, ctx );
4016 return LDAP_SUCCESS;
4019 if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4021 if( val->bv_val[0] != '(' /*')'*/ &&
4022 val->bv_val[0] != '{' /*'}'*/ )
4024 return LDAP_INVALID_SYNTAX;
4027 /* trim leading white space */
4029 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
4035 /* grab next word */
4036 comp.bv_val = &val->bv_val[len];
4037 len = val->bv_len - len;
4038 for( comp.bv_len = 0;
4039 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
4045 if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
4046 rc = numericoidValidate( NULL, &comp );
4047 } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
4048 rc = integerValidate( NULL, &comp );
4050 rc = LDAP_INVALID_SYNTAX;
4054 if( rc == LDAP_SUCCESS ) {
4055 ber_dupbv_x( normalized, &comp, ctx );
4061 static char *country_gen_syn[] = {
4062 "1.3.6.1.4.1.1466.115.121.1.15",
4063 "1.3.6.1.4.1.1466.115.121.1.26",
4064 "1.3.6.1.4.1.1466.115.121.1.44",
4068 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
4069 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
4071 static slap_syntax_defs_rec syntax_defs[] = {
4072 {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
4073 X_BINARY X_NOT_H_R ")",
4074 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
4075 {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
4076 0, NULL, NULL, NULL},
4077 {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
4078 0, NULL, NULL, NULL},
4079 {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
4081 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4082 {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
4084 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4085 {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
4086 0, NULL, bitStringValidate, NULL },
4087 {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
4088 0, NULL, booleanValidate, NULL},
4089 {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
4090 X_BINARY X_NOT_H_R ")",
4091 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4092 NULL, certificateValidate, NULL},
4093 {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
4094 X_BINARY X_NOT_H_R ")",
4095 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4096 NULL, sequenceValidate, NULL},
4097 {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4098 X_BINARY X_NOT_H_R ")",
4099 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4100 NULL, sequenceValidate, NULL},
4101 #if 0 /* need to go __after__ printableString */
4102 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4103 0, "1.3.6.1.4.1.1466.115.121.1.44",
4104 countryStringValidate, NULL},
4106 {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4107 0, NULL, dnValidate, dnPretty},
4108 {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
4109 0, NULL, rdnValidate, rdnPretty},
4110 #ifdef LDAP_COMP_MATCH
4111 {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
4112 0, NULL, allComponentsValidate, NULL},
4113 {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
4114 0, NULL, componentFilterValidate, NULL},
4116 {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4117 0, NULL, NULL, NULL},
4118 {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4119 0, NULL, deliveryMethodValidate, NULL},
4120 {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4121 0, NULL, UTF8StringValidate, NULL},
4122 {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4123 0, NULL, NULL, NULL},
4124 {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4125 0, NULL, NULL, NULL},
4126 {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4127 0, NULL, NULL, NULL},
4128 {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4129 0, NULL, NULL, NULL},
4130 {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4131 0, NULL, NULL, NULL},
4132 {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4133 0, NULL, printablesStringValidate, NULL},
4134 {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4135 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
4136 {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4137 0, NULL, generalizedTimeValidate, NULL},
4138 {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4139 0, NULL, NULL, NULL},
4140 {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4141 0, NULL, IA5StringValidate, NULL},
4142 {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4143 0, NULL, integerValidate, NULL},
4144 {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4145 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4146 {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4147 0, NULL, NULL, NULL},
4148 {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4149 0, NULL, NULL, NULL},
4150 {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4151 0, NULL, NULL, NULL},
4152 {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4153 0, NULL, NULL, NULL},
4154 {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4155 0, NULL, NULL, NULL},
4156 {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4157 0, NULL, nameUIDValidate, nameUIDPretty },
4158 {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4159 0, NULL, NULL, NULL},
4160 {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4161 0, NULL, numericStringValidate, NULL},
4162 {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4163 0, NULL, NULL, NULL},
4164 {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4165 0, NULL, numericoidValidate, NULL},
4166 {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4167 0, NULL, IA5StringValidate, NULL},
4168 {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4169 0, NULL, blobValidate, NULL},
4170 {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4171 0, NULL, UTF8StringValidate, NULL},
4172 {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4173 0, NULL, NULL, NULL},
4174 {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4175 0, NULL, NULL, NULL},
4176 {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4177 0, NULL, printableStringValidate, NULL},
4178 /* moved here because now depends on Directory String, IA5 String
4179 * and Printable String */
4180 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4181 0, country_gen_syn, countryStringValidate, NULL},
4182 {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
4183 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
4184 0, NULL, subtreeSpecificationValidate, NULL},
4185 {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4186 X_BINARY X_NOT_H_R ")",
4187 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4188 {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4189 0, NULL, printableStringValidate, NULL},
4190 {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4191 0, NULL, NULL, NULL},
4192 {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4193 0, NULL, printablesStringValidate, NULL},
4194 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4195 {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4196 0, NULL, utcTimeValidate, NULL},
4198 {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4199 0, NULL, NULL, NULL},
4200 {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4201 0, NULL, NULL, NULL},
4202 {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4203 0, NULL, NULL, NULL},
4204 {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4205 0, NULL, NULL, NULL},
4206 {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4207 0, NULL, NULL, NULL},
4209 /* RFC 2307 NIS Syntaxes */
4210 {"( 1.3.6.1.1.1.0.0 DESC 'RFC2307 NIS Netgroup Triple' )",
4211 0, NULL, nisNetgroupTripleValidate, NULL},
4212 {"( 1.3.6.1.1.1.0.1 DESC 'RFC2307 Boot Parameter' )",
4213 0, NULL, bootParameterValidate, NULL},
4215 /* draft-zeilenga-ldap-x509 */
4216 {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
4217 SLAP_SYNTAX_HIDE, NULL,
4218 serialNumberAndIssuerValidate,
4219 serialNumberAndIssuerPretty},
4220 {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
4221 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4222 {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
4223 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4224 {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
4225 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4226 {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
4227 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4228 {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
4229 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4230 {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
4231 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4233 #ifdef SLAPD_AUTHPASSWD
4234 /* needs updating */
4235 {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4236 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4239 {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
4240 0, NULL, UUIDValidate, UUIDPretty},
4242 {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
4243 SLAP_SYNTAX_HIDE, NULL, csnValidate, NULL},
4245 /* OpenLDAP Void Syntax */
4246 {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4247 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
4249 /* FIXME: OID is unused, but not registered yet */
4250 {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
4251 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
4253 {NULL, 0, NULL, NULL, NULL}
4256 char *certificateExactMatchSyntaxes[] = {
4257 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4260 #ifdef LDAP_COMP_MATCH
4261 char *componentFilterMatchSyntaxes[] = {
4262 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4266 char *directoryStringSyntaxes[] = {
4267 "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
4270 char *integerFirstComponentMatchSyntaxes[] = {
4271 "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
4272 "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
4275 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
4276 "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
4277 "1.3.6.1.4.1.1466.115.121.1.3" /* attributeTypeDescription */,
4278 "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
4279 "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
4280 "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
4281 "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
4282 "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
4283 "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
4288 * Other matching rules in X.520 that we do not use (yet):
4290 * 2.5.13.25 uTCTimeMatch
4291 * 2.5.13.26 uTCTimeOrderingMatch
4292 * 2.5.13.31* directoryStringFirstComponentMatch
4293 * 2.5.13.32* wordMatch
4294 * 2.5.13.33* keywordMatch
4295 * 2.5.13.36+ certificatePairExactMatch
4296 * 2.5.13.37+ certificatePairMatch
4297 * 2.5.13.38+ certificateListExactMatch
4298 * 2.5.13.39+ certificateListMatch
4299 * 2.5.13.40+ algorithmIdentifierMatch
4300 * 2.5.13.41* storedPrefixMatch
4301 * 2.5.13.42 attributeCertificateMatch
4302 * 2.5.13.43 readerAndKeyIDMatch
4303 * 2.5.13.44 attributeIntegrityMatch
4305 * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
4306 * (+) described in draft-zeilenga-ldap-x509
4308 static slap_mrule_defs_rec mrule_defs[] = {
4310 * EQUALITY matching rules must be listed after associated APPROX
4311 * matching rules. So, we list all APPROX matching rules first.
4313 {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4314 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4315 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4316 NULL, NULL, directoryStringApproxMatch,
4317 directoryStringApproxIndexer, directoryStringApproxFilter,
4320 {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4321 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4322 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4323 NULL, NULL, IA5StringApproxMatch,
4324 IA5StringApproxIndexer, IA5StringApproxFilter,
4328 * Other matching rules
4331 {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4332 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4333 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4334 NULL, NULL, octetStringMatch,
4335 octetStringIndexer, octetStringFilter,
4338 {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4339 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4340 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4341 NULL, dnNormalize, dnMatch,
4342 octetStringIndexer, octetStringFilter,
4345 {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
4346 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4347 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4348 NULL, dnNormalize, dnRelativeMatch,
4352 {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
4353 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4354 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4355 NULL, dnNormalize, dnRelativeMatch,
4359 {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
4360 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4361 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4362 NULL, dnNormalize, dnRelativeMatch,
4366 {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
4367 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4368 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4369 NULL, dnNormalize, dnRelativeMatch,
4373 {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
4374 "SYNTAX 1.2.36.79672281.1.5.0 )",
4375 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4376 NULL, rdnNormalize, rdnMatch,
4377 octetStringIndexer, octetStringFilter,
4380 #ifdef LDAP_COMP_MATCH
4381 {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
4382 "SYNTAX 1.2.36.79672281.1.5.2 )",
4383 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
4384 NULL, NULL , componentFilterMatch,
4385 octetStringIndexer, octetStringFilter,
4388 {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
4389 "SYNTAX 1.2.36.79672281.1.5.3 )",
4390 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4391 NULL, NULL , allComponentsMatch,
4392 octetStringIndexer, octetStringFilter,
4395 {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
4396 "SYNTAX 1.2.36.79672281.1.5.3 )",
4397 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4398 NULL, NULL , directoryComponentsMatch,
4399 octetStringIndexer, octetStringFilter,
4403 {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4404 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4405 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4406 NULL, UTF8StringNormalize, octetStringMatch,
4407 octetStringIndexer, octetStringFilter,
4408 directoryStringApproxMatchOID },
4410 {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4411 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4412 SLAP_MR_ORDERING, directoryStringSyntaxes,
4413 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4415 "caseIgnoreMatch" },
4417 {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4418 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4419 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4420 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4421 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4422 "caseIgnoreMatch" },
4424 {"( 2.5.13.5 NAME 'caseExactMatch' "
4425 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4426 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4427 NULL, UTF8StringNormalize, octetStringMatch,
4428 octetStringIndexer, octetStringFilter,
4429 directoryStringApproxMatchOID },
4431 {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4432 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4433 SLAP_MR_ORDERING, directoryStringSyntaxes,
4434 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4438 {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4439 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4440 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4441 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4442 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4445 {"( 2.5.13.8 NAME 'numericStringMatch' "
4446 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4447 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4448 NULL, numericStringNormalize, octetStringMatch,
4449 octetStringIndexer, octetStringFilter,
4452 {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
4453 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4454 SLAP_MR_ORDERING, NULL,
4455 NULL, numericStringNormalize, octetStringOrderingMatch,
4457 "numericStringMatch" },
4459 {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4460 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4461 SLAP_MR_SUBSTR, NULL,
4462 NULL, numericStringNormalize, octetStringSubstringsMatch,
4463 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4464 "numericStringMatch" },
4466 {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4467 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4468 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4469 NULL, NULL, NULL, NULL, NULL, NULL },
4471 {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4472 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4473 SLAP_MR_SUBSTR, NULL,
4474 NULL, NULL, NULL, NULL, NULL,
4475 "caseIgnoreListMatch" },
4477 {"( 2.5.13.13 NAME 'booleanMatch' "
4478 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
4479 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4480 NULL, NULL, booleanMatch,
4481 octetStringIndexer, octetStringFilter,
4484 {"( 2.5.13.14 NAME 'integerMatch' "
4485 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4486 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4487 NULL, NULL, integerMatch,
4488 octetStringIndexer, octetStringFilter,
4491 {"( 2.5.13.15 NAME 'integerOrderingMatch' "
4492 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4493 SLAP_MR_ORDERING, NULL,
4494 NULL, NULL, integerMatch,
4498 {"( 2.5.13.16 NAME 'bitStringMatch' "
4499 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
4500 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4501 NULL, NULL, octetStringMatch,
4502 octetStringIndexer, octetStringFilter,
4505 {"( 2.5.13.17 NAME 'octetStringMatch' "
4506 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4507 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4508 NULL, NULL, octetStringMatch,
4509 octetStringIndexer, octetStringFilter,
4512 {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
4513 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4514 SLAP_MR_ORDERING, NULL,
4515 NULL, NULL, octetStringOrderingMatch,
4517 "octetStringMatch" },
4519 {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
4520 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4521 SLAP_MR_SUBSTR, NULL,
4522 NULL, NULL, octetStringSubstringsMatch,
4523 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4524 "octetStringMatch" },
4526 {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
4527 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
4528 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4530 telephoneNumberNormalize, octetStringMatch,
4531 octetStringIndexer, octetStringFilter,
4534 {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
4535 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4536 SLAP_MR_SUBSTR, NULL,
4537 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
4538 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4539 "telephoneNumberMatch" },
4541 {"( 2.5.13.22 NAME 'presentationAddressMatch' "
4542 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
4543 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4544 NULL, NULL, NULL, NULL, NULL, NULL },
4546 {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
4547 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
4548 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4549 NULL, uniqueMemberNormalize, uniqueMemberMatch,
4550 uniqueMemberIndexer, uniqueMemberFilter,
4553 {"( 2.5.13.24 NAME 'protocolInformationMatch' "
4554 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
4555 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4556 NULL, NULL, NULL, NULL, NULL, NULL },
4558 {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
4559 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4560 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
4561 NULL, generalizedTimeNormalize, octetStringMatch,
4562 generalizedTimeIndexer, generalizedTimeFilter,
4565 {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
4566 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
4567 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
4568 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
4570 "generalizedTimeMatch" },
4572 {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
4573 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4574 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4575 integerFirstComponentMatchSyntaxes,
4576 NULL, firstComponentNormalize, integerMatch,
4577 octetStringIndexer, octetStringFilter,
4580 {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
4581 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4582 SLAP_MR_EQUALITY | SLAP_MR_EXT,
4583 objectIdentifierFirstComponentMatchSyntaxes,
4584 NULL, firstComponentNormalize, octetStringMatch,
4585 octetStringIndexer, octetStringFilter,
4588 {"( 2.5.13.34 NAME 'certificateExactMatch' "
4589 "SYNTAX 1.3.6.1.1.15.1 )",
4590 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
4591 NULL, certificateExactNormalize, octetStringMatch,
4592 octetStringIndexer, octetStringFilter,
4595 {"( 2.5.13.35 NAME 'certificateMatch' "
4596 "SYNTAX 1.3.6.1.1.15.2 )",
4597 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4598 NULL, NULL, NULL, NULL, NULL,
4601 {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
4602 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4603 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4604 NULL, IA5StringNormalize, octetStringMatch,
4605 octetStringIndexer, octetStringFilter,
4606 IA5StringApproxMatchOID },
4608 {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
4609 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4610 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4611 NULL, IA5StringNormalize, octetStringMatch,
4612 octetStringIndexer, octetStringFilter,
4613 IA5StringApproxMatchOID },
4615 {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
4616 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4617 SLAP_MR_SUBSTR, NULL,
4618 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
4619 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4620 "caseIgnoreIA5Match" },
4622 {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
4623 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4624 SLAP_MR_SUBSTR, NULL,
4625 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
4626 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4627 "caseExactIA5Match" },
4629 #ifdef SLAPD_AUTHPASSWD
4630 /* needs updating */
4631 {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
4632 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
4633 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
4634 NULL, NULL, authPasswordMatch,
4639 {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
4640 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4642 NULL, NULL, integerBitAndMatch,
4646 {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
4647 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
4649 NULL, NULL, integerBitOrMatch,
4653 {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
4654 "SYNTAX 1.3.6.1.1.16.1 )",
4655 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
4656 NULL, UUIDNormalize, octetStringMatch,
4657 octetStringIndexer, octetStringFilter,
4660 {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
4661 "SYNTAX 1.3.6.1.1.16.1 )",
4662 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
4663 NULL, UUIDNormalize, octetStringOrderingMatch,
4664 octetStringIndexer, octetStringFilter,
4667 {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
4668 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
4669 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
4670 NULL, NULL, csnMatch,
4671 csnIndexer, csnFilter,
4674 {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
4675 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
4676 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
4677 NULL, NULL, csnOrderingMatch,
4681 /* FIXME: OID is unused, but not registered yet */
4682 {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
4683 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
4684 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
4685 NULL, authzNormalize, authzMatch,
4689 {NULL, SLAP_MR_NONE, NULL,
4690 NULL, NULL, NULL, NULL, NULL,
4695 slap_schema_init( void )
4700 /* we should only be called once (from main) */
4701 assert( schema_init_done == 0 );
4703 for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
4704 res = register_syntax( &syntax_defs[i] );
4707 fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
4708 syntax_defs[i].sd_desc );
4713 for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
4714 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
4715 mrule_defs[i].mrd_compat_syntaxes == NULL )
4718 "slap_schema_init: Ignoring unusable matching rule %s\n",
4719 mrule_defs[i].mrd_desc );
4723 res = register_matching_rule( &mrule_defs[i] );
4727 "slap_schema_init: Error registering matching rule %s\n",
4728 mrule_defs[i].mrd_desc );
4733 res = slap_schema_load();
4734 schema_init_done = 1;
4739 schema_destroy( void )
4748 if( schema_init_done ) {
4749 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
4750 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );