1 /* schema_init.c - init builtin schema */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2006 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>
31 #include "ldap_utf8.h"
34 #include <openssl/x509.h>
35 #include <openssl/err.h>
36 #include <openssl/rsa.h>
37 #include <openssl/crypto.h>
38 #include <openssl/pem.h>
39 #include <openssl/bio.h>
40 #include <openssl/asn1.h>
41 #include <openssl/x509v3.h>
42 #include <openssl/ssl.h>
46 #include "lutil_hash.h"
47 #define HASH_BYTES LUTIL_HASH_BYTES
48 #define HASH_CONTEXT lutil_HASH_CTX
49 #define HASH_Init(c) lutil_HASHInit(c)
50 #define HASH_Update(c,buf,len) lutil_HASHUpdate(c,buf,len)
51 #define HASH_Final(d,c) lutil_HASHFinal(d,c)
53 /* approx matching rules */
54 #define directoryStringApproxMatchOID "1.3.6.1.4.1.4203.666.4.4"
55 #define directoryStringApproxMatch approxMatch
56 #define directoryStringApproxIndexer approxIndexer
57 #define directoryStringApproxFilter approxFilter
58 #define IA5StringApproxMatchOID "1.3.6.1.4.1.4203.666.4.5"
59 #define IA5StringApproxMatch approxMatch
60 #define IA5StringApproxIndexer approxIndexer
61 #define IA5StringApproxFilter approxFilter
63 /* Change Sequence Number (CSN) - much of this will change */
64 #define csnValidate blobValidate
65 #define csnMatch octetStringMatch
66 #define csnOrderingMatch octetStringOrderingMatch
67 #define csnIndexer generalizedTimeIndexer
68 #define csnFilter generalizedTimeFilter
70 #ifdef SLAP_AUTHZ_SYNTAX
71 /* FIXME: temporary */
72 #define authzMatch octetStringMatch
73 #endif /* SLAP_AUTHZ_SYNTAX */
75 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
76 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
77 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
78 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
80 ldap_pvt_thread_mutex_t ad_undef_mutex;
81 ldap_pvt_thread_mutex_t oc_undef_mutex;
88 /* no value allowed */
89 return LDAP_INVALID_SYNTAX;
97 /* any value allowed */
101 #define berValidate blobValidate
108 if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
109 if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
116 static int certificateValidate( Syntax *syntax, struct berval *in )
119 unsigned char *p = (unsigned char *)in->bv_val;
121 xcert = d2i_X509(NULL, &p, in->bv_len);
122 if ( !xcert ) return LDAP_INVALID_SYNTAX;
127 #define certificateValidate sequenceValidate
136 struct berval *value,
137 void *assertedValue )
139 struct berval *asserted = (struct berval *) assertedValue;
140 int match = value->bv_len - asserted->bv_len;
143 match = memcmp( value->bv_val, asserted->bv_val, value->bv_len );
151 octetStringOrderingMatch(
156 struct berval *value,
157 void *assertedValue )
159 struct berval *asserted = (struct berval *) assertedValue;
160 ber_len_t v_len = value->bv_len;
161 ber_len_t av_len = asserted->bv_len;
163 int match = memcmp( value->bv_val, asserted->bv_val,
164 (v_len < av_len ? v_len : av_len) );
166 if( match == 0 ) match = v_len - av_len;
174 HASH_CONTEXT *HASHcontext,
175 struct berval *prefix,
180 HASH_Init(HASHcontext);
181 if(prefix && prefix->bv_len > 0) {
182 HASH_Update(HASHcontext,
183 (unsigned char *)prefix->bv_val, prefix->bv_len);
185 if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
186 HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
187 HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
193 HASH_CONTEXT *HASHcontext,
194 unsigned char *HASHdigest,
195 unsigned char *value,
198 HASH_CONTEXT ctx = *HASHcontext;
199 HASH_Update( &ctx, value, len );
200 HASH_Final( HASHdigest, &ctx );
203 /* Index generation function */
204 int octetStringIndexer(
209 struct berval *prefix,
217 HASH_CONTEXT HASHcontext;
218 unsigned char HASHdigest[HASH_BYTES];
219 struct berval digest;
220 digest.bv_val = (char *)HASHdigest;
221 digest.bv_len = sizeof(HASHdigest);
223 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
224 /* just count them */
227 /* we should have at least one value at this point */
230 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
232 slen = syntax->ssyn_oidlen;
233 mlen = mr->smr_oidlen;
235 hashPreset( &HASHcontext, prefix, 0, syntax, mr);
236 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
237 hashIter( &HASHcontext, HASHdigest,
238 (unsigned char *)values[i].bv_val, values[i].bv_len );
239 ber_dupbv_x( &keys[i], &digest, ctx );
242 BER_BVZERO( &keys[i] );
249 /* Index generation function */
250 int octetStringFilter(
255 struct berval *prefix,
256 void * assertedValue,
262 HASH_CONTEXT HASHcontext;
263 unsigned char HASHdigest[HASH_BYTES];
264 struct berval *value = (struct berval *) assertedValue;
265 struct berval digest;
266 digest.bv_val = (char *)HASHdigest;
267 digest.bv_len = sizeof(HASHdigest);
269 slen = syntax->ssyn_oidlen;
270 mlen = mr->smr_oidlen;
272 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
274 hashPreset( &HASHcontext, prefix, 0, syntax, mr );
275 hashIter( &HASHcontext, HASHdigest,
276 (unsigned char *)value->bv_val, value->bv_len );
278 ber_dupbv_x( keys, &digest, ctx );
279 BER_BVZERO( &keys[1] );
287 octetStringSubstringsMatch(
292 struct berval *value,
293 void *assertedValue )
296 SubstringsAssertion *sub = assertedValue;
297 struct berval left = *value;
301 /* Add up asserted input length */
302 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
303 inlen += sub->sa_initial.bv_len;
306 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
307 inlen += sub->sa_any[i].bv_len;
310 if ( !BER_BVISNULL( &sub->sa_final ) ) {
311 inlen += sub->sa_final.bv_len;
314 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
315 if ( inlen > left.bv_len ) {
320 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
321 sub->sa_initial.bv_len );
327 left.bv_val += sub->sa_initial.bv_len;
328 left.bv_len -= sub->sa_initial.bv_len;
329 inlen -= sub->sa_initial.bv_len;
332 if ( !BER_BVISNULL( &sub->sa_final ) ) {
333 if ( inlen > left.bv_len ) {
338 match = memcmp( sub->sa_final.bv_val,
339 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
340 sub->sa_final.bv_len );
346 left.bv_len -= sub->sa_final.bv_len;
347 inlen -= sub->sa_final.bv_len;
351 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
356 if ( inlen > left.bv_len ) {
357 /* not enough length */
362 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
366 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
373 idx = p - left.bv_val;
375 if ( idx >= left.bv_len ) {
376 /* this shouldn't happen */
383 if ( sub->sa_any[i].bv_len > left.bv_len ) {
384 /* not enough left */
389 match = memcmp( left.bv_val,
390 sub->sa_any[i].bv_val,
391 sub->sa_any[i].bv_len );
399 left.bv_val += sub->sa_any[i].bv_len;
400 left.bv_len -= sub->sa_any[i].bv_len;
401 inlen -= sub->sa_any[i].bv_len;
410 /* Substrings Index generation function */
412 octetStringSubstringsIndexer(
417 struct berval *prefix,
426 HASH_CONTEXT HCany, HCini, HCfin;
427 unsigned char HASHdigest[HASH_BYTES];
428 struct berval digest;
429 digest.bv_val = (char *)HASHdigest;
430 digest.bv_len = sizeof(HASHdigest);
434 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
435 /* count number of indices to generate */
436 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
437 if( values[i].bv_len >= index_substr_if_maxlen ) {
438 nkeys += index_substr_if_maxlen -
439 (index_substr_if_minlen - 1);
440 } else if( values[i].bv_len >= index_substr_if_minlen ) {
441 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
445 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
446 if( values[i].bv_len >= index_substr_any_len ) {
447 nkeys += values[i].bv_len - (index_substr_any_len - 1);
451 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
452 if( values[i].bv_len >= index_substr_if_maxlen ) {
453 nkeys += index_substr_if_maxlen -
454 (index_substr_if_minlen - 1);
455 } else if( values[i].bv_len >= index_substr_if_minlen ) {
456 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
462 /* no keys to generate */
467 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
469 slen = syntax->ssyn_oidlen;
470 mlen = mr->smr_oidlen;
472 if ( flags & SLAP_INDEX_SUBSTR_ANY )
473 hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
474 if( flags & SLAP_INDEX_SUBSTR_INITIAL )
475 hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
476 if( flags & SLAP_INDEX_SUBSTR_FINAL )
477 hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
480 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
483 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
484 ( values[i].bv_len >= index_substr_any_len ) )
486 max = values[i].bv_len - (index_substr_any_len - 1);
488 for( j=0; j<max; j++ ) {
489 hashIter( &HCany, HASHdigest,
490 (unsigned char *)&values[i].bv_val[j],
491 index_substr_any_len );
492 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
496 /* skip if too short */
497 if( values[i].bv_len < index_substr_if_minlen ) continue;
499 max = index_substr_if_maxlen < values[i].bv_len
500 ? index_substr_if_maxlen : values[i].bv_len;
502 for( j=index_substr_if_minlen; j<=max; j++ ) {
504 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
505 hashIter( &HCini, HASHdigest,
506 (unsigned char *)values[i].bv_val, j );
507 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
510 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
511 hashIter( &HCfin, HASHdigest,
512 (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
513 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
520 BER_BVZERO( &keys[nkeys] );
531 octetStringSubstringsFilter (
536 struct berval *prefix,
537 void * assertedValue,
541 SubstringsAssertion *sa;
544 size_t slen, mlen, klen;
546 HASH_CONTEXT HASHcontext;
547 unsigned char HASHdigest[HASH_BYTES];
548 struct berval *value;
549 struct berval digest;
551 sa = (SubstringsAssertion *) assertedValue;
553 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
554 !BER_BVISNULL( &sa->sa_initial ) &&
555 sa->sa_initial.bv_len >= index_substr_if_minlen )
558 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
559 ( flags & SLAP_INDEX_SUBSTR_ANY ))
561 nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
565 if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
567 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
568 if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
569 /* don't bother accounting with stepping */
570 nkeys += sa->sa_any[i].bv_len -
571 ( index_substr_any_len - 1 );
576 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
577 !BER_BVISNULL( &sa->sa_final ) &&
578 sa->sa_final.bv_len >= index_substr_if_minlen )
581 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
582 ( flags & SLAP_INDEX_SUBSTR_ANY ))
584 nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
593 digest.bv_val = (char *)HASHdigest;
594 digest.bv_len = sizeof(HASHdigest);
596 slen = syntax->ssyn_oidlen;
597 mlen = mr->smr_oidlen;
599 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
602 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
603 !BER_BVISNULL( &sa->sa_initial ) &&
604 sa->sa_initial.bv_len >= index_substr_if_minlen )
606 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
607 value = &sa->sa_initial;
609 klen = index_substr_if_maxlen < value->bv_len
610 ? index_substr_if_maxlen : value->bv_len;
612 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
613 hashIter( &HASHcontext, HASHdigest,
614 (unsigned char *)value->bv_val, klen );
615 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
617 /* If initial is too long and we have subany indexed, use it
618 * to match the excess...
620 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
623 pre = SLAP_INDEX_SUBSTR_PREFIX;
624 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
625 for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
627 hashIter( &HASHcontext, HASHdigest,
628 (unsigned char *)&value->bv_val[j], index_substr_any_len );
629 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
634 if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
636 pre = SLAP_INDEX_SUBSTR_PREFIX;
637 klen = index_substr_any_len;
639 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
640 if( sa->sa_any[i].bv_len < index_substr_any_len ) {
644 value = &sa->sa_any[i];
646 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
648 j <= value->bv_len - index_substr_any_len;
649 j += index_substr_any_step )
651 hashIter( &HASHcontext, HASHdigest,
652 (unsigned char *)&value->bv_val[j], klen );
653 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
658 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
659 !BER_BVISNULL( &sa->sa_final ) &&
660 sa->sa_final.bv_len >= index_substr_if_minlen )
662 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
663 value = &sa->sa_final;
665 klen = index_substr_if_maxlen < value->bv_len
666 ? index_substr_if_maxlen : value->bv_len;
668 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
669 hashIter( &HASHcontext, HASHdigest,
670 (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
671 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
673 /* If final is too long and we have subany indexed, use it
674 * to match the excess...
676 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
679 pre = SLAP_INDEX_SUBSTR_PREFIX;
680 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
681 for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
683 hashIter( &HASHcontext, HASHdigest,
684 (unsigned char *)&value->bv_val[j], index_substr_any_len );
685 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
691 BER_BVZERO( &keys[nkeys] );
708 /* very unforgiving validation, requires no normalization
709 * before simplistic matching
711 if( in->bv_len < 3 ) {
712 return LDAP_INVALID_SYNTAX;
716 * RFC 2252 section 6.3 Bit String
717 * bitstring = "'" *binary-digit "'B"
718 * binary-digit = "0" / "1"
719 * example: '0101111101'B
722 if( in->bv_val[0] != '\'' ||
723 in->bv_val[in->bv_len - 2] != '\'' ||
724 in->bv_val[in->bv_len - 1] != 'B' )
726 return LDAP_INVALID_SYNTAX;
729 for( i = in->bv_len - 3; i > 0; i-- ) {
730 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
731 return LDAP_INVALID_SYNTAX;
739 * Syntax is [RFC2252]:
744 ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
746 Values in this syntax are encoded according to the following BNF:
748 bitstring = "'" *binary-digit "'B"
750 binary-digit = "0" / "1"
754 6.21. Name And Optional UID
756 ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
758 Values in this syntax are encoded according to the following BNF:
760 NameAndOptionalUID = DistinguishedName [ "#" bitstring ]
762 Although the '#' character may occur in a string representation of a
763 distinguished name, no additional special quoting is done. This
764 syntax has been added subsequent to RFC 1778.
768 1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
771 * draft-ietf-ldapbis-syntaxes-xx.txt says:
776 A value of the Bit String syntax is a sequence of binary digits. The
777 LDAP-specific encoding of a value of this syntax is defined by the
780 BitString = SQUOTE *binary-digit SQUOTE "B"
782 binary-digit = "0" / "1"
784 The <SQUOTE> rule is defined in [MODELS].
789 The LDAP definition for the Bit String syntax is:
791 ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
793 This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
797 3.3.21. Name and Optional UID
799 A value of the Name and Optional UID syntax is the distinguished name
800 [MODELS] of an entity optionally accompanied by a unique identifier
801 that serves to differentiate the entity from others with an identical
804 The LDAP-specific encoding of a value of this syntax is defined by
807 NameAndOptionalUID = distinguishedName [ SHARP BitString ]
809 The <BitString> rule is defined in Section 3.3.2. The
810 <distinguishedName> rule is defined in [LDAPDN]. The <SHARP> rule is
813 Note that although the '#' character may occur in the string
814 representation of a distinguished name, no additional escaping of
815 this character is performed when a <distinguishedName> is encoded in
816 a <NameAndOptionalUID>.
819 1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
821 The LDAP definition for the Name and Optional UID syntax is:
823 ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
825 This syntax corresponds to the NameAndOptionalUID ASN.1 type from
829 * draft-ietf-ldapbis-models-xx.txt [MODELS] says:
832 1.4. Common ABNF Productions
835 SHARP = %x23 ; octothorpe (or sharp sign) ("#")
837 SQUOTE = %x27 ; single quote ("'")
841 * Note: normalization strips any leading "0"s, unless the
842 * bit string is exactly "'0'B", so the normalized example,
843 * in slapd, would result in
845 * 1.3.6.1.4.1.1466.0=#04024869,o=test,c=gb#'101'B
847 * Since draft-ietf-ldapbis-dn-xx.txt clarifies that SHARP,
848 * i.e. "#", doesn't have to be escaped except when at the
849 * beginning of a value, the definition of Name and Optional
850 * UID appears to be flawed, because there is no clear means
851 * to determine whether the UID part is present or not.
855 * cn=Someone,dc=example,dc=com#'1'B
857 * could be either a NameAndOptionalUID with trailing UID, i.e.
859 * DN = "cn=Someone,dc=example,dc=com"
862 * or a NameAndOptionalUID with no trailing UID, and the AVA
863 * in the last RDN made of
866 * attributeValue = com#'1'B
868 * in fact "com#'1'B" is a valid IA5 string.
870 * As a consequence, current slapd code assumes that the
871 * presence of portions of a BitString at the end of the string
872 * representation of a NameAndOptionalUID means a BitString
873 * is expected, and cause an error otherwise. This is quite
874 * arbitrary, and might change in the future.
884 struct berval dn, uid;
886 if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
888 ber_dupbv( &dn, in );
889 if( !dn.bv_val ) return LDAP_OTHER;
891 /* if there's a "#", try bitStringValidate()... */
892 uid.bv_val = strrchr( dn.bv_val, '#' );
893 if ( !BER_BVISNULL( &uid ) ) {
895 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
897 rc = bitStringValidate( NULL, &uid );
898 if ( rc == LDAP_SUCCESS ) {
899 /* in case of success, trim the UID,
900 * otherwise treat it as part of the DN */
901 dn.bv_len -= uid.bv_len + 1;
902 uid.bv_val[-1] = '\0';
906 rc = dnValidate( NULL, &dn );
908 ber_memfree( dn.bv_val );
919 assert( val != NULL );
920 assert( out != NULL );
923 Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
925 if( BER_BVISEMPTY( val ) ) {
926 ber_dupbv_x( out, val, ctx );
928 } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
929 return LDAP_INVALID_SYNTAX;
933 struct berval dnval = *val;
934 struct berval uidval = BER_BVNULL;
936 uidval.bv_val = strrchr( val->bv_val, '#' );
937 if ( !BER_BVISNULL( &uidval ) ) {
939 uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
941 rc = bitStringValidate( NULL, &uidval );
943 if ( rc == LDAP_SUCCESS ) {
944 ber_dupbv_x( &dnval, val, ctx );
945 dnval.bv_len -= uidval.bv_len + 1;
946 dnval.bv_val[dnval.bv_len] = '\0';
949 BER_BVZERO( &uidval );
953 rc = dnPretty( syntax, &dnval, out, ctx );
954 if ( dnval.bv_val != val->bv_val ) {
955 slap_sl_free( dnval.bv_val, ctx );
957 if( rc != LDAP_SUCCESS ) {
961 if( !BER_BVISNULL( &uidval ) ) {
965 tmp = slap_sl_realloc( out->bv_val, out->bv_len
966 + STRLENOF( "#" ) + uidval.bv_len + 1,
969 ber_memfree_x( out->bv_val, ctx );
973 out->bv_val[out->bv_len++] = '#';
974 out->bv_val[out->bv_len++] = '\'';
976 got1 = uidval.bv_len < sizeof("'0'B");
977 for( i = 1; i < uidval.bv_len - 2; i++ ) {
978 c = uidval.bv_val[i];
981 if( got1 ) out->bv_val[out->bv_len++] = c;
985 out->bv_val[out->bv_len++] = c;
990 out->bv_val[out->bv_len++] = '\'';
991 out->bv_val[out->bv_len++] = 'B';
992 out->bv_val[out->bv_len] = '\0';
996 Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1002 uniqueMemberNormalize(
1007 struct berval *normalized,
1013 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ));
1015 ber_dupbv_x( &out, val, ctx );
1016 if ( BER_BVISEMPTY( &out ) ) {
1020 struct berval uid = BER_BVNULL;
1022 uid.bv_val = strrchr( out.bv_val, '#' );
1023 if ( !BER_BVISNULL( &uid ) ) {
1025 uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1027 rc = bitStringValidate( NULL, &uid );
1028 if ( rc == LDAP_SUCCESS ) {
1029 uid.bv_val[-1] = '\0';
1030 out.bv_len -= uid.bv_len + 1;
1036 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1038 if( rc != LDAP_SUCCESS ) {
1039 slap_sl_free( out.bv_val, ctx );
1040 return LDAP_INVALID_SYNTAX;
1043 if( !BER_BVISNULL( &uid ) ) {
1046 tmp = ch_realloc( normalized->bv_val,
1047 normalized->bv_len + uid.bv_len
1048 + STRLENOF("#") + 1 );
1049 if ( tmp == NULL ) {
1050 ber_memfree_x( normalized->bv_val, ctx );
1054 normalized->bv_val = tmp;
1056 /* insert the separator */
1057 normalized->bv_val[normalized->bv_len++] = '#';
1059 /* append the UID */
1060 AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1061 uid.bv_val, uid.bv_len );
1062 normalized->bv_len += uid.bv_len;
1065 normalized->bv_val[normalized->bv_len] = '\0';
1068 slap_sl_free( out.bv_val, ctx );
1071 return LDAP_SUCCESS;
1080 struct berval *value,
1081 void *assertedValue )
1084 struct berval *asserted = (struct berval *) assertedValue;
1085 struct berval assertedDN = *asserted;
1086 struct berval assertedUID = BER_BVNULL;
1087 struct berval valueDN = *value;
1088 struct berval valueUID = BER_BVNULL;
1089 int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1091 if ( !BER_BVISEMPTY( asserted ) ) {
1092 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1093 if ( !BER_BVISNULL( &assertedUID ) ) {
1094 assertedUID.bv_val++;
1095 assertedUID.bv_len = assertedDN.bv_len
1096 - ( assertedUID.bv_val - assertedDN.bv_val );
1098 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1099 assertedDN.bv_len -= assertedUID.bv_len + 1;
1102 BER_BVZERO( &assertedUID );
1107 if ( !BER_BVISEMPTY( value ) ) {
1109 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1110 if ( !BER_BVISNULL( &valueUID ) ) {
1112 valueUID.bv_len = valueDN.bv_len
1113 - ( valueUID.bv_val - valueDN.bv_val );
1115 if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1116 valueDN.bv_len -= valueUID.bv_len + 1;
1119 BER_BVZERO( &valueUID );
1124 if( valueUID.bv_len && assertedUID.bv_len ) {
1125 match = valueUID.bv_len - assertedUID.bv_len;
1128 return LDAP_SUCCESS;
1131 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1134 return LDAP_SUCCESS;
1137 } else if ( !approx && valueUID.bv_len ) {
1140 return LDAP_SUCCESS;
1142 } else if ( !approx && assertedUID.bv_len ) {
1145 return LDAP_SUCCESS;
1148 return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1152 uniqueMemberIndexer(
1157 struct berval *prefix,
1165 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1166 /* just count them */
1170 dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1172 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1173 struct berval assertedDN = values[i];
1174 struct berval assertedUID = BER_BVNULL;
1176 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1177 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1178 if ( !BER_BVISNULL( &assertedUID ) ) {
1179 assertedUID.bv_val++;
1180 assertedUID.bv_len = assertedDN.bv_len
1181 - ( assertedUID.bv_val - assertedDN.bv_val );
1183 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1184 assertedDN.bv_len -= assertedUID.bv_len + 1;
1187 BER_BVZERO( &assertedUID );
1192 dnvalues[i] = assertedDN;
1194 BER_BVZERO( &dnvalues[i] );
1196 rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1197 dnvalues, keysp, ctx );
1199 slap_sl_free( dnvalues, ctx );
1209 struct berval *prefix,
1210 void * assertedValue,
1214 struct berval *asserted = (struct berval *) assertedValue;
1215 struct berval assertedDN = *asserted;
1216 struct berval assertedUID = BER_BVNULL;
1218 if ( !BER_BVISEMPTY( asserted ) ) {
1219 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1220 if ( !BER_BVISNULL( &assertedUID ) ) {
1221 assertedUID.bv_val++;
1222 assertedUID.bv_len = assertedDN.bv_len
1223 - ( assertedUID.bv_val - assertedDN.bv_val );
1225 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1226 assertedDN.bv_len -= assertedUID.bv_len + 1;
1229 BER_BVZERO( &assertedUID );
1234 return octetStringFilter( use, flags, syntax, mr, prefix,
1235 &assertedDN, keysp, ctx );
1240 * Handling boolean syntax and matching is quite rigid.
1241 * A more flexible approach would be to allow a variety
1242 * of strings to be normalized and prettied into TRUE
1250 /* very unforgiving validation, requires no normalization
1251 * before simplistic matching
1254 if( in->bv_len == 4 ) {
1255 if( bvmatch( in, &slap_true_bv ) ) {
1256 return LDAP_SUCCESS;
1258 } else if( in->bv_len == 5 ) {
1259 if( bvmatch( in, &slap_false_bv ) ) {
1260 return LDAP_SUCCESS;
1264 return LDAP_INVALID_SYNTAX;
1273 struct berval *value,
1274 void *assertedValue )
1276 /* simplistic matching allowed by rigid validation */
1277 struct berval *asserted = (struct berval *) assertedValue;
1278 *matchp = value->bv_len != asserted->bv_len;
1279 return LDAP_SUCCESS;
1282 /*-------------------------------------------------------------------
1283 LDAP/X.500 string syntax / matching rules have a few oddities. This
1284 comment attempts to detail how slapd(8) treats them.
1287 StringSyntax X.500 LDAP Matching/Comments
1288 DirectoryString CHOICE UTF8 i/e + ignore insignificant spaces
1289 PrintableString subset subset i/e + ignore insignificant spaces
1290 PrintableString subset subset i/e + ignore insignificant spaces
1291 NumericString subset subset ignore all spaces
1292 IA5String ASCII ASCII i/e + ignore insignificant spaces
1293 TeletexString T.61 T.61 i/e + ignore insignificant spaces
1295 TelephoneNumber subset subset i + ignore all spaces and "-"
1297 See draft-ietf-ldapbis-strpro for details (once published).
1301 In X.500(93), a directory string can be either a PrintableString,
1302 a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1303 In later versions, more CHOICEs were added. In all cases the string
1306 In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1307 A directory string cannot be zero length.
1309 For matching, there are both case ignore and exact rules. Both
1310 also require that "insignificant" spaces be ignored.
1311 spaces before the first non-space are ignored;
1312 spaces after the last non-space are ignored;
1313 spaces after a space are ignored.
1314 Note: by these rules (and as clarified in X.520), a string of only
1315 spaces is to be treated as if held one space, not empty (which
1316 would be a syntax error).
1319 In ASN.1, numeric string is just a string of digits and spaces
1320 and could be empty. However, in X.500, all attribute values of
1321 numeric string carry a non-empty constraint. For example:
1323 internationalISDNNumber ATTRIBUTE ::= {
1324 WITH SYNTAX InternationalISDNNumber
1325 EQUALITY MATCHING RULE numericStringMatch
1326 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1327 ID id-at-internationalISDNNumber }
1328 InternationalISDNNumber ::=
1329 NumericString (SIZE(1..ub-international-isdn-number))
1331 Unforunately, some assertion values are don't carry the same
1332 constraint (but its unclear how such an assertion could ever
1333 be true). In LDAP, there is one syntax (numericString) not two
1334 (numericString with constraint, numericString without constraint).
1335 This should be treated as numericString with non-empty constraint.
1336 Note that while someone may have no ISDN number, there are no ISDN
1337 numbers which are zero length.
1339 In matching, spaces are ignored.
1342 In ASN.1, Printable string is just a string of printable characters
1343 and can be empty. In X.500, semantics much like NumericString (see
1344 serialNumber for a like example) excepting uses insignificant space
1345 handling instead of ignore all spaces.
1348 Basically same as PrintableString. There are no examples in X.500,
1349 but same logic applies. So we require them to be non-empty as
1352 -------------------------------------------------------------------*/
1361 unsigned char *u = (unsigned char *)in->bv_val;
1363 if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1364 /* directory strings cannot be empty */
1365 return LDAP_INVALID_SYNTAX;
1368 for( count = in->bv_len; count > 0; count -= len, u += len ) {
1369 /* get the length indicated by the first byte */
1370 len = LDAP_UTF8_CHARLEN2( u, len );
1372 /* very basic checks */
1375 if( (u[5] & 0xC0) != 0x80 ) {
1376 return LDAP_INVALID_SYNTAX;
1379 if( (u[4] & 0xC0) != 0x80 ) {
1380 return LDAP_INVALID_SYNTAX;
1383 if( (u[3] & 0xC0) != 0x80 ) {
1384 return LDAP_INVALID_SYNTAX;
1387 if( (u[2] & 0xC0 )!= 0x80 ) {
1388 return LDAP_INVALID_SYNTAX;
1391 if( (u[1] & 0xC0) != 0x80 ) {
1392 return LDAP_INVALID_SYNTAX;
1395 /* CHARLEN already validated it */
1398 return LDAP_INVALID_SYNTAX;
1401 /* make sure len corresponds with the offset
1402 to the next character */
1403 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1407 return LDAP_INVALID_SYNTAX;
1410 return LDAP_SUCCESS;
1414 UTF8StringNormalize(
1419 struct berval *normalized,
1422 struct berval tmp, nvalue;
1426 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
1428 if( BER_BVISNULL( val ) ) {
1429 /* assume we're dealing with a syntax (e.g., UTF8String)
1430 * which allows empty strings
1432 BER_BVZERO( normalized );
1433 return LDAP_SUCCESS;
1436 flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1437 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1438 flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1439 ? LDAP_UTF8_APPROX : 0;
1441 val = UTF8bvnormalize( val, &tmp, flags, ctx );
1446 /* collapse spaces (in place) */
1448 nvalue.bv_val = tmp.bv_val;
1450 /* trim leading spaces? */
1451 wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1452 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1454 for( i = 0; i < tmp.bv_len; i++) {
1455 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1456 if( wasspace++ == 0 ) {
1457 /* trim repeated spaces */
1458 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1462 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1466 if( !BER_BVISEMPTY( &nvalue ) ) {
1467 /* trim trailing space? */
1469 (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1470 ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1474 nvalue.bv_val[nvalue.bv_len] = '\0';
1477 /* string of all spaces is treated as one space */
1478 nvalue.bv_val[0] = ' ';
1479 nvalue.bv_val[1] = '\0';
1483 *normalized = nvalue;
1484 return LDAP_SUCCESS;
1488 directoryStringSubstringsMatch(
1493 struct berval *value,
1494 void *assertedValue )
1497 SubstringsAssertion *sub = assertedValue;
1498 struct berval left = *value;
1502 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1503 if ( sub->sa_initial.bv_len > left.bv_len ) {
1504 /* not enough left */
1509 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1510 sub->sa_initial.bv_len );
1516 left.bv_val += sub->sa_initial.bv_len;
1517 left.bv_len -= sub->sa_initial.bv_len;
1519 priorspace = ASCII_SPACE(
1520 sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1523 if ( sub->sa_any ) {
1524 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1528 if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] )
1529 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1531 /* allow next space to match */
1538 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1542 if ( sub->sa_any[i].bv_len > left.bv_len ) {
1543 /* not enough left */
1548 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1555 idx = p - left.bv_val;
1557 if ( idx >= left.bv_len ) {
1558 /* this shouldn't happen */
1565 if ( sub->sa_any[i].bv_len > left.bv_len ) {
1566 /* not enough left */
1571 match = memcmp( left.bv_val,
1572 sub->sa_any[i].bv_val,
1573 sub->sa_any[i].bv_len );
1581 left.bv_val += sub->sa_any[i].bv_len;
1582 left.bv_len -= sub->sa_any[i].bv_len;
1584 priorspace = ASCII_SPACE(
1585 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1589 if ( !BER_BVISNULL( &sub->sa_final ) ) {
1590 if( priorspace && !BER_BVISEMPTY( &sub->sa_final )
1591 && ASCII_SPACE( sub->sa_final.bv_val[0] ))
1593 /* allow next space to match */
1598 if ( sub->sa_final.bv_len > left.bv_len ) {
1599 /* not enough left */
1604 match = memcmp( sub->sa_final.bv_val,
1605 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1606 sub->sa_final.bv_len );
1615 return LDAP_SUCCESS;
1618 #if defined(SLAPD_APPROX_INITIALS)
1619 # define SLAPD_APPROX_DELIMITER "._ "
1620 # define SLAPD_APPROX_WORDLEN 2
1622 # define SLAPD_APPROX_DELIMITER " "
1623 # define SLAPD_APPROX_WORDLEN 1
1632 struct berval *value,
1633 void *assertedValue )
1635 struct berval *nval, *assertv;
1636 char *val, **values, **words, *c;
1637 int i, count, len, nextchunk=0, nextavail=0;
1639 /* Yes, this is necessary */
1640 nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
1641 if( nval == NULL ) {
1643 return LDAP_SUCCESS;
1646 /* Yes, this is necessary */
1647 assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1648 NULL, LDAP_UTF8_APPROX, NULL );
1649 if( assertv == NULL ) {
1652 return LDAP_SUCCESS;
1655 /* Isolate how many words there are */
1656 for ( c = nval->bv_val, count = 1; *c; c++ ) {
1657 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1658 if ( c == NULL ) break;
1663 /* Get a phonetic copy of each word */
1664 words = (char **)ch_malloc( count * sizeof(char *) );
1665 values = (char **)ch_malloc( count * sizeof(char *) );
1666 for ( c = nval->bv_val, i = 0; i < count; i++, c += strlen(c) + 1 ) {
1668 values[i] = phonetic(c);
1671 /* Work through the asserted value's words, to see if at least some
1672 of the words are there, in the same order. */
1674 while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1675 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1680 #if defined(SLAPD_APPROX_INITIALS)
1681 else if( len == 1 ) {
1682 /* Single letter words need to at least match one word's initial */
1683 for( i=nextavail; i<count; i++ )
1684 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1691 /* Isolate the next word in the asserted value and phonetic it */
1692 assertv->bv_val[nextchunk+len] = '\0';
1693 val = phonetic( assertv->bv_val + nextchunk );
1695 /* See if this phonetic chunk is in the remaining words of *value */
1696 for( i=nextavail; i<count; i++ ){
1697 if( !strcmp( val, values[i] ) ){
1705 /* This chunk in the asserted value was NOT within the *value. */
1711 /* Go on to the next word in the asserted value */
1715 /* If some of the words were seen, call it a match */
1716 if( nextavail > 0 ) {
1723 /* Cleanup allocs */
1724 ber_bvfree( assertv );
1725 for( i=0; i<count; i++ ) {
1726 ch_free( values[i] );
1732 return LDAP_SUCCESS;
1741 struct berval *prefix,
1747 int i,j, len, wordcount, keycount=0;
1748 struct berval *newkeys;
1749 BerVarray keys=NULL;
1751 for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
1752 struct berval val = BER_BVNULL;
1753 /* Yes, this is necessary */
1754 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
1755 assert( !BER_BVISNULL( &val ) );
1757 /* Isolate how many words there are. There will be a key for each */
1758 for( wordcount = 0, c = val.bv_val; *c; c++) {
1759 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1760 if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1762 if (*c == '\0') break;
1766 /* Allocate/increase storage to account for new keys */
1767 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1)
1768 * sizeof(struct berval) );
1769 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1770 if( keys ) ch_free( keys );
1773 /* Get a phonetic copy of each word */
1774 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1776 if( len < SLAPD_APPROX_WORDLEN ) continue;
1777 ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1782 ber_memfree( val.bv_val );
1784 BER_BVZERO( &keys[keycount] );
1787 return LDAP_SUCCESS;
1796 struct berval *prefix,
1797 void * assertedValue,
1806 /* Yes, this is necessary */
1807 val = UTF8bvnormalize( ((struct berval *)assertedValue),
1808 NULL, LDAP_UTF8_APPROX, NULL );
1809 if( val == NULL || BER_BVISNULL( val ) ) {
1810 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1811 BER_BVZERO( &keys[0] );
1814 return LDAP_SUCCESS;
1817 /* Isolate how many words there are. There will be a key for each */
1818 for( count = 0,c = val->bv_val; *c; c++) {
1819 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1820 if( len >= SLAPD_APPROX_WORDLEN ) count++;
1822 if (*c == '\0') break;
1826 /* Allocate storage for new keys */
1827 keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1829 /* Get a phonetic copy of each word */
1830 for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1832 if( len < SLAPD_APPROX_WORDLEN ) continue;
1833 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1839 BER_BVZERO( &keys[count] );
1842 return LDAP_SUCCESS;
1845 /* Remove all spaces and '-' characters */
1847 telephoneNumberNormalize(
1852 struct berval *normalized,
1857 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ));
1859 /* validator should have refused an empty string */
1860 assert( !BER_BVISEMPTY( val ) );
1862 q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
1864 for( p = val->bv_val; *p; p++ ) {
1865 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1871 normalized->bv_len = q - normalized->bv_val;
1873 if( BER_BVISEMPTY( normalized ) ) {
1874 slap_sl_free( normalized->bv_val, ctx );
1875 BER_BVZERO( normalized );
1876 return LDAP_INVALID_SYNTAX;
1879 return LDAP_SUCCESS;
1887 struct berval val = *in;
1889 if( BER_BVISEMPTY( &val ) ) {
1890 /* disallow empty strings */
1891 return LDAP_INVALID_SYNTAX;
1894 while( OID_LEADCHAR( val.bv_val[0] ) ) {
1895 if ( val.bv_len == 1 ) {
1896 return LDAP_SUCCESS;
1899 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
1906 while ( OID_LEADCHAR( val.bv_val[0] )) {
1910 if ( val.bv_len == 0 ) {
1911 return LDAP_SUCCESS;
1915 if( !OID_SEPARATOR( val.bv_val[0] )) {
1923 return LDAP_INVALID_SYNTAX;
1932 struct berval val = *in;
1934 if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
1936 if ( val.bv_val[0] == '-' ) {
1940 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
1941 return LDAP_INVALID_SYNTAX;
1944 if( val.bv_val[0] == '0' ) { /* "-0" */
1945 return LDAP_INVALID_SYNTAX;
1948 } else if ( val.bv_val[0] == '0' ) {
1949 if( val.bv_len > 1 ) { /* "0<more>" */
1950 return LDAP_INVALID_SYNTAX;
1953 return LDAP_SUCCESS;
1956 for( i=0; i < val.bv_len; i++ ) {
1957 if( !ASCII_DIGIT(val.bv_val[i]) ) {
1958 return LDAP_INVALID_SYNTAX;
1962 return LDAP_SUCCESS;
1971 struct berval *value,
1972 void *assertedValue )
1974 struct berval *asserted = (struct berval *) assertedValue;
1975 int vsign = 1, asign = 1; /* default sign = '+' */
1980 if( v.bv_val[0] == '-' ) {
1986 if( BER_BVISEMPTY( &v ) ) vsign = 0;
1989 if( a.bv_val[0] == '-' ) {
1995 if( BER_BVISEMPTY( &a ) ) vsign = 0;
1997 match = vsign - asign;
1999 match = ( v.bv_len != a.bv_len
2000 ? ( v.bv_len < a.bv_len ? -1 : 1 )
2001 : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2002 if( vsign < 0 ) match = -match;
2006 return LDAP_SUCCESS;
2010 countryStringValidate(
2012 struct berval *val )
2014 if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2016 if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2017 return LDAP_INVALID_SYNTAX;
2019 if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2020 return LDAP_INVALID_SYNTAX;
2023 return LDAP_SUCCESS;
2027 printableStringValidate(
2029 struct berval *val )
2033 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2035 for(i=0; i < val->bv_len; i++) {
2036 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2037 return LDAP_INVALID_SYNTAX;
2041 return LDAP_SUCCESS;
2045 printablesStringValidate(
2047 struct berval *val )
2051 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2053 for(i=0,len=0; i < val->bv_len; i++) {
2054 int c = val->bv_val[i];
2058 return LDAP_INVALID_SYNTAX;
2062 } else if ( SLAP_PRINTABLE(c) ) {
2065 return LDAP_INVALID_SYNTAX;
2070 return LDAP_INVALID_SYNTAX;
2073 return LDAP_SUCCESS;
2079 struct berval *val )
2083 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2085 for(i=0; i < val->bv_len; i++) {
2086 if( !LDAP_ASCII(val->bv_val[i]) ) {
2087 return LDAP_INVALID_SYNTAX;
2091 return LDAP_SUCCESS;
2100 struct berval *normalized,
2104 int casefold = !SLAP_MR_ASSOCIATED(mr, slap_schema.si_mr_caseExactIA5Match);
2106 assert( !BER_BVISEMPTY( val ) );
2108 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ));
2112 /* Ignore initial whitespace */
2113 while ( ASCII_SPACE( *p ) ) p++;
2115 normalized->bv_val = ber_strdup_x( p, ctx );
2116 p = q = normalized->bv_val;
2119 if ( ASCII_SPACE( *p ) ) {
2122 /* Ignore the extra whitespace */
2123 while ( ASCII_SPACE( *p ) ) {
2127 } else if ( casefold ) {
2128 /* Most IA5 rules require casefolding */
2129 *q++ = TOLOWER(*p); p++;
2136 assert( normalized->bv_val <= p );
2140 * If the string ended in space, backup the pointer one
2141 * position. One is enough because the above loop collapsed
2142 * all whitespace to a single space.
2144 if ( ASCII_SPACE( q[-1] ) ) --q;
2146 /* null terminate */
2149 normalized->bv_len = q - normalized->bv_val;
2150 if( BER_BVISEMPTY( normalized ) ) {
2151 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2152 normalized->bv_val[0] = ' ';
2153 normalized->bv_val[1] = '\0';
2154 normalized->bv_len = 1;
2157 return LDAP_SUCCESS;
2166 if( in->bv_len != 36 ) {
2167 return LDAP_INVALID_SYNTAX;
2170 for( i=0; i<36; i++ ) {
2176 if( in->bv_val[i] != '-' ) {
2177 return LDAP_INVALID_SYNTAX;
2181 if( !ASCII_HEX( in->bv_val[i]) ) {
2182 return LDAP_INVALID_SYNTAX;
2187 return LDAP_SUCCESS;
2198 int rc=LDAP_INVALID_SYNTAX;
2200 assert( in != NULL );
2201 assert( out != NULL );
2203 if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2206 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2208 for( i=0; i<36; i++ ) {
2214 if( in->bv_val[i] != '-' ) {
2217 out->bv_val[i] = '-';
2221 if( !ASCII_HEX( in->bv_val[i]) ) {
2224 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2229 out->bv_val[ out->bv_len ] = '\0';
2233 slap_sl_free( out->bv_val, ctx );
2246 struct berval *normalized,
2249 unsigned char octet = '\0';
2252 normalized->bv_len = 16;
2253 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2255 for( i=0, j=0; i<36; i++ ) {
2256 unsigned char nibble;
2257 if( val->bv_val[i] == '-' ) {
2260 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2261 nibble = val->bv_val[i] - '0';
2263 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2264 nibble = val->bv_val[i] - ('a'-10);
2266 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2267 nibble = val->bv_val[i] - ('A'-10);
2270 slap_sl_free( normalized->bv_val, ctx );
2271 return LDAP_INVALID_SYNTAX;
2276 normalized->bv_val[j>>1] = octet;
2278 octet = nibble << 4;
2283 normalized->bv_val[normalized->bv_len] = 0;
2284 return LDAP_SUCCESS;
2290 numericStringValidate(
2296 if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2298 for(i=0; i < in->bv_len; i++) {
2299 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2300 return LDAP_INVALID_SYNTAX;
2304 return LDAP_SUCCESS;
2308 numericStringNormalize(
2313 struct berval *normalized,
2316 /* removal all spaces */
2319 assert( !BER_BVISEMPTY( val ) );
2321 normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2324 q = normalized->bv_val;
2327 if ( ASCII_SPACE( *p ) ) {
2328 /* Ignore whitespace */
2335 /* we should have copied no more then is in val */
2336 assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2338 /* null terminate */
2341 normalized->bv_len = q - normalized->bv_val;
2343 if( BER_BVISEMPTY( normalized ) ) {
2344 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2345 normalized->bv_val[0] = ' ';
2346 normalized->bv_val[1] = '\0';
2347 normalized->bv_len = 1;
2350 return LDAP_SUCCESS;
2354 * Integer conversion macros that will use the largest available
2357 #if defined(HAVE_STRTOLL) && defined(LLONG_MAX) \
2358 && defined(LLONG_MIN) && defined(HAVE_LONG_LONG)
2359 # define SLAP_STRTOL(n,e,b) strtoll(n,e,b)
2360 # define SLAP_LONG_MAX LLONG_MAX
2361 # define SLAP_LONG_MIN LLONG_MIN
2362 # define SLAP_LONG long long
2364 # define SLAP_STRTOL(n,e,b) strtol(n,e,b)
2365 # define SLAP_LONG_MAX LONG_MAX
2366 # define SLAP_LONG_MIN LONG_MIN
2367 # define SLAP_LONG long
2368 #endif /* HAVE_STRTOLL ... */
2376 struct berval *value,
2377 void *assertedValue )
2379 SLAP_LONG lValue, lAssertedValue;
2381 /* safe to assume integers are NUL terminated? */
2382 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2383 if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX) &&
2386 return LDAP_CONSTRAINT_VIOLATION;
2389 lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2391 if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX ) &&
2394 return LDAP_CONSTRAINT_VIOLATION;
2397 *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2398 return LDAP_SUCCESS;
2407 struct berval *value,
2408 void *assertedValue )
2410 SLAP_LONG lValue, lAssertedValue;
2412 /* safe to assume integers are NUL terminated? */
2413 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2414 if(( lValue == SLAP_LONG_MIN || lValue == SLAP_LONG_MAX ) &&
2417 return LDAP_CONSTRAINT_VIOLATION;
2420 lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2422 if(( lAssertedValue == SLAP_LONG_MIN || lAssertedValue == SLAP_LONG_MAX ) &&
2425 return LDAP_CONSTRAINT_VIOLATION;
2428 *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2429 return LDAP_SUCCESS;
2433 serialNumberAndIssuerValidate(
2439 struct berval sn, i;
2440 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2442 i.bv_val = ber_bvchr( in, '$' );
2443 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2445 sn.bv_val = in->bv_val;
2446 sn.bv_len = i.bv_val - in->bv_val;
2449 i.bv_len = in->bv_len - (sn.bv_len + 1);
2451 /* validate serial number (strict for now) */
2452 for( n=0; n < sn.bv_len; n++ ) {
2453 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2457 rc = dnValidate( NULL, &i );
2458 if( rc ) return LDAP_INVALID_SYNTAX;
2460 return LDAP_SUCCESS;
2464 serialNumberAndIssuerPretty(
2472 struct berval sn, i, newi;
2474 assert( val != NULL );
2475 assert( out != NULL );
2477 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
2478 val->bv_val, 0, 0 );
2480 if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2482 i.bv_val = ber_bvchr( val, '$' );
2483 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2485 sn.bv_val = val->bv_val;
2486 sn.bv_len = i.bv_val - val->bv_val;
2489 i.bv_len = val->bv_len - (sn.bv_len + 1);
2491 /* eat leading zeros */
2492 for( n=0; n < (sn.bv_len-1); n++ ) {
2493 if( sn.bv_val[n] != '0' ) break;
2498 for( n=0; n < sn.bv_len; n++ ) {
2499 if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2503 rc = dnPretty( syntax, &i, &newi, ctx );
2504 if( rc ) return LDAP_INVALID_SYNTAX;
2506 /* make room from sn + "$" */
2507 out->bv_len = sn.bv_len + newi.bv_len + 1;
2508 out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2510 if( out->bv_val == NULL ) {
2512 slap_sl_free( newi.bv_val, ctx );
2516 /* push issuer over */
2517 AC_MEMCPY( &out->bv_val[sn.bv_len+1], out->bv_val, newi.bv_len );
2518 /* insert sn and "$" */
2519 AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2520 out->bv_val[sn.bv_len] = '$';
2522 out->bv_val[out->bv_len] = '\0';
2524 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
2525 out->bv_val, 0, 0 );
2527 return LDAP_SUCCESS;
2531 * This routine is called by certificateExactNormalize when
2532 * certificateExactNormalize receives a search string instead of
2533 * a certificate. This routine checks if the search value is valid
2534 * and then returns the normalized value
2537 serialNumberAndIssuerNormalize(
2547 struct berval sn, i, newi;
2549 assert( val != NULL );
2550 assert( out != NULL );
2552 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
2553 val->bv_val, 0, 0 );
2555 if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2557 i.bv_val = ber_bvchr( val, '$' );
2558 if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
2560 sn.bv_val = val->bv_val;
2561 sn.bv_len = i.bv_val - val->bv_val;
2564 i.bv_len = val->bv_len - (sn.bv_len + 1);
2566 /* eat leading zeros */
2567 for( n=0; n < (sn.bv_len-1); n++ ) {
2568 if( sn.bv_val[n] != '0' ) break;
2573 for( n=0; n < sn.bv_len; n++ ) {
2574 if( !ASCII_DIGIT(sn.bv_val[n]) ) {
2575 return LDAP_INVALID_SYNTAX;
2580 rc = dnNormalize( usage, syntax, mr, &i, &newi, ctx );
2581 if( rc ) return LDAP_INVALID_SYNTAX;
2583 /* make room from sn + "$" */
2584 out->bv_len = sn.bv_len + newi.bv_len + 1;
2585 out->bv_val = slap_sl_realloc( newi.bv_val, out->bv_len + 1, ctx );
2587 if( out->bv_val == NULL ) {
2589 slap_sl_free( newi.bv_val, ctx );
2593 /* push issuer over */
2594 AC_MEMCPY( &out->bv_val[sn.bv_len+1], out->bv_val, newi.bv_len );
2595 /* insert sn and "$" */
2596 AC_MEMCPY( out->bv_val, sn.bv_val, sn.bv_len );
2597 out->bv_val[sn.bv_len] = '$';
2599 out->bv_val[out->bv_len] = '\0';
2601 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
2602 out->bv_val, 0, 0 );
2609 certificateExactNormalize(
2614 struct berval *normalized,
2617 int rc = LDAP_INVALID_SYNTAX;
2619 char *serial = NULL;
2620 ber_len_t seriallen;
2621 struct berval issuer_dn = BER_BVNULL;
2622 X509_NAME *name = NULL;
2623 ASN1_INTEGER *sn = NULL;
2626 if( BER_BVISEMPTY( val ) ) goto done;
2628 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
2629 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
2632 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) );
2634 p = (unsigned char *)val->bv_val;
2635 xcert = d2i_X509( NULL, &p, val->bv_len);
2636 if( xcert == NULL ) goto done;
2638 sn=X509_get_serialNumber(xcert);
2639 if ( sn == NULL ) goto done;
2640 serial=i2s_ASN1_INTEGER(0, sn );
2641 if( serial == NULL ) goto done;
2642 seriallen=strlen(serial);
2644 name=X509_get_issuer_name(xcert);
2645 if( name == NULL ) goto done;
2646 rc = dnX509normalize( name, &issuer_dn );
2647 if( rc != LDAP_SUCCESS ) goto done;
2649 normalized->bv_len = seriallen + issuer_dn.bv_len + 1;
2650 normalized->bv_val = ch_malloc(normalized->bv_len+1);
2651 p = (unsigned char *)normalized->bv_val;
2652 AC_MEMCPY(p, serial, seriallen);
2655 AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
2656 p += issuer_dn.bv_len;
2659 Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
2660 normalized->bv_val, NULL, NULL );
2663 if (xcert) X509_free(xcert);
2664 if (serial) ch_free(serial);
2665 if (issuer_dn.bv_val) ber_memfree(issuer_dn.bv_val);
2669 #endif /* HAVE_TLS */
2672 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
2673 /* slight optimization - does not need the start parameter */
2674 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
2679 check_time_syntax (struct berval *val,
2682 struct berval *fraction)
2685 * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
2686 * start=1 UTCTime YYmmddHHMM[SS][Z|(+/-)HHMM]
2687 * GeneralizedTime supports leap seconds, UTCTime does not.
2689 static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
2690 static const int mdays[2][12] = {
2691 /* non-leap years */
2692 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
2694 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
2697 int part, c, c1, c2, tzoffset, leapyear = 0;
2700 e = p + val->bv_len;
2702 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2703 parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
2705 for (part = start; part < 7 && p < e; part++) {
2707 if (!ASCII_DIGIT(c1)) {
2712 return LDAP_INVALID_SYNTAX;
2715 if (!ASCII_DIGIT(c)) {
2716 return LDAP_INVALID_SYNTAX;
2718 c += c1 * 10 - '0' * 11;
2719 if ((part | 1) == 3) {
2722 return LDAP_INVALID_SYNTAX;
2725 if (c >= ceiling[part]) {
2726 if (! (c == 60 && part == 6 && start == 0))
2727 return LDAP_INVALID_SYNTAX;
2731 if (part < 5 + start) {
2732 return LDAP_INVALID_SYNTAX;
2734 for (; part < 9; part++) {
2738 /* leapyear check for the Gregorian calendar (year>1581) */
2739 if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
2743 if (parts[3] >= mdays[leapyear][parts[2]]) {
2744 return LDAP_INVALID_SYNTAX;
2748 fraction->bv_val = p;
2749 fraction->bv_len = 0;
2750 if (p < e && (*p == '.' || *p == ',')) {
2752 while (++p < e && ASCII_DIGIT(*p)) {
2755 if (p - fraction->bv_val == 1) {
2756 return LDAP_INVALID_SYNTAX;
2758 for (end_num = p; end_num[-1] == '0'; --end_num) {
2761 c = end_num - fraction->bv_val;
2762 if (c != 1) fraction->bv_len = c;
2768 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2774 return LDAP_INVALID_SYNTAX;
2780 for (part = 7; part < 9 && p < e; part++) {
2782 if (!ASCII_DIGIT(c1)) {
2787 return LDAP_INVALID_SYNTAX;
2790 if (!ASCII_DIGIT(c2)) {
2791 return LDAP_INVALID_SYNTAX;
2793 parts[part] = c1 * 10 + c2 - '0' * 11;
2794 if (parts[part] >= ceiling[part]) {
2795 return LDAP_INVALID_SYNTAX;
2798 if (part < 8 + start) {
2799 return LDAP_INVALID_SYNTAX;
2802 if (tzoffset == '-') {
2803 /* negative offset to UTC, ie west of Greenwich */
2804 parts[4] += parts[7];
2805 parts[5] += parts[8];
2806 /* offset is just hhmm, no seconds */
2807 for (part = 6; --part >= 0; ) {
2811 c = mdays[leapyear][parts[2]];
2813 if (parts[part] >= c) {
2815 return LDAP_INVALID_SYNTAX;
2820 } else if (part != 5) {
2825 /* positive offset to UTC, ie east of Greenwich */
2826 parts[4] -= parts[7];
2827 parts[5] -= parts[8];
2828 for (part = 6; --part >= 0; ) {
2829 if (parts[part] < 0) {
2831 return LDAP_INVALID_SYNTAX;
2836 /* make first arg to % non-negative */
2837 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
2842 } else if (part != 5) {
2849 return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
2852 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
2859 struct berval *normalized )
2863 rc = check_time_syntax(val, 1, parts, NULL);
2864 if (rc != LDAP_SUCCESS) {
2868 normalized->bv_val = ch_malloc( 14 );
2869 if ( normalized->bv_val == NULL ) {
2870 return LBER_ERROR_MEMORY;
2873 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
2874 parts[1], parts[2] + 1, parts[3] + 1,
2875 parts[4], parts[5], parts[6] );
2876 normalized->bv_len = 13;
2878 return LDAP_SUCCESS;
2888 return check_time_syntax(in, 1, parts, NULL);
2891 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
2894 generalizedTimeValidate(
2899 struct berval fraction;
2900 return check_time_syntax(in, 0, parts, &fraction);
2904 generalizedTimeNormalize(
2909 struct berval *normalized,
2914 struct berval fraction;
2916 rc = check_time_syntax(val, 0, parts, &fraction);
2917 if (rc != LDAP_SUCCESS) {
2921 len = sizeof("YYYYmmddHHMMSSZ")-1 + fraction.bv_len;
2922 normalized->bv_val = slap_sl_malloc( len + 1, ctx );
2923 if ( BER_BVISNULL( normalized ) ) {
2924 return LBER_ERROR_MEMORY;
2927 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
2928 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
2929 parts[4], parts[5], parts[6] );
2930 if ( !BER_BVISEMPTY( &fraction ) ) {
2931 memcpy( normalized->bv_val + sizeof("YYYYmmddHHMMSSZ")-2,
2932 fraction.bv_val, fraction.bv_len );
2933 normalized->bv_val[sizeof("YYYYmmddHHMMSSZ")-2] = '.';
2935 strcpy( normalized->bv_val + len-1, "Z" );
2936 normalized->bv_len = len;
2938 return LDAP_SUCCESS;
2942 generalizedTimeOrderingMatch(
2947 struct berval *value,
2948 void *assertedValue )
2950 struct berval *asserted = (struct berval *) assertedValue;
2951 ber_len_t v_len = value->bv_len;
2952 ber_len_t av_len = asserted->bv_len;
2954 /* ignore trailing 'Z' when comparing */
2955 int match = memcmp( value->bv_val, asserted->bv_val,
2956 (v_len < av_len ? v_len : av_len) - 1 );
2957 if ( match == 0 ) match = v_len - av_len;
2960 return LDAP_SUCCESS;
2963 /* Index generation function */
2964 int generalizedTimeIndexer(
2969 struct berval *prefix,
2977 BerValue bvtmp; /* 40 bit index */
2979 struct lutil_timet tt;
2981 bvtmp.bv_len = sizeof(tmp);
2983 for( i=0; values[i].bv_val != NULL; i++ ) {
2984 /* just count them */
2987 /* we should have at least one value at this point */
2990 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2992 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
2993 for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
2994 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
2995 /* Use 40 bits of time for key */
2996 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
2997 lutil_tm2time( &tm, &tt );
2998 tmp[0] = tt.tt_gsec & 0xff;
2999 tmp[4] = tt.tt_sec & 0xff;
3001 tmp[3] = tt.tt_sec & 0xff;
3003 tmp[2] = tt.tt_sec & 0xff;
3005 tmp[1] = tt.tt_sec & 0xff;
3007 ber_dupbv_x(&keys[j++], &bvtmp, ctx );
3011 keys[j].bv_val = NULL;
3016 return LDAP_SUCCESS;
3019 /* Index generation function */
3020 int generalizedTimeFilter(
3025 struct berval *prefix,
3026 void * assertedValue,
3032 BerValue bvtmp; /* 40 bit index */
3033 BerValue *value = (BerValue *) assertedValue;
3035 struct lutil_timet tt;
3037 bvtmp.bv_len = sizeof(tmp);
3039 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
3040 /* Use 40 bits of time for key */
3041 if ( value->bv_val && value->bv_len >= 10 &&
3042 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
3044 lutil_tm2time( &tm, &tt );
3045 tmp[0] = tt.tt_gsec & 0xff;
3046 tmp[4] = tt.tt_sec & 0xff;
3048 tmp[3] = tt.tt_sec & 0xff;
3050 tmp[2] = tt.tt_sec & 0xff;
3052 tmp[1] = tt.tt_sec & 0xff;
3054 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
3055 ber_dupbv_x(keys, &bvtmp, ctx );
3056 keys[1].bv_val = NULL;
3064 return LDAP_SUCCESS;
3068 deliveryMethodValidate(
3070 struct berval *val )
3073 #define LENOF(s) (sizeof(s)-1)
3074 struct berval tmp = *val;
3076 * DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
3077 * pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
3078 * "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
3081 if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3083 switch( tmp.bv_val[0] ) {
3086 if(( tmp.bv_len >= LENOF("any") ) &&
3087 ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
3089 tmp.bv_len -= LENOF("any");
3090 tmp.bv_val += LENOF("any");
3093 return LDAP_INVALID_SYNTAX;
3097 if(( tmp.bv_len >= LENOF("mhs") ) &&
3098 ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
3100 tmp.bv_len -= LENOF("mhs");
3101 tmp.bv_val += LENOF("mhs");
3104 return LDAP_INVALID_SYNTAX;
3108 if(( tmp.bv_len >= LENOF("physical") ) &&
3109 ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
3111 tmp.bv_len -= LENOF("physical");
3112 tmp.bv_val += LENOF("physical");
3115 return LDAP_INVALID_SYNTAX;
3118 case 'T': /* telex or teletex or telephone */
3119 if(( tmp.bv_len >= LENOF("telex") ) &&
3120 ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
3122 tmp.bv_len -= LENOF("telex");
3123 tmp.bv_val += LENOF("telex");
3126 if(( tmp.bv_len >= LENOF("teletex") ) &&
3127 ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
3129 tmp.bv_len -= LENOF("teletex");
3130 tmp.bv_val += LENOF("teletex");
3133 if(( tmp.bv_len >= LENOF("telephone") ) &&
3134 ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
3136 tmp.bv_len -= LENOF("telephone");
3137 tmp.bv_val += LENOF("telephone");
3140 return LDAP_INVALID_SYNTAX;
3143 case 'G': /* g3fax or g4fax */
3144 if(( tmp.bv_len >= LENOF("g3fax") ) && (
3145 ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
3146 ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
3148 tmp.bv_len -= LENOF("g3fax");
3149 tmp.bv_val += LENOF("g3fax");
3152 return LDAP_INVALID_SYNTAX;
3156 if(( tmp.bv_len >= LENOF("ia5") ) &&
3157 ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
3159 tmp.bv_len -= LENOF("ia5");
3160 tmp.bv_val += LENOF("ia5");
3163 return LDAP_INVALID_SYNTAX;
3167 if(( tmp.bv_len >= LENOF("videotex") ) &&
3168 ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
3170 tmp.bv_len -= LENOF("videotex");
3171 tmp.bv_val += LENOF("videotex");
3174 return LDAP_INVALID_SYNTAX;
3177 return LDAP_INVALID_SYNTAX;
3180 if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
3182 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3186 if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
3190 return LDAP_INVALID_SYNTAX;
3192 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
3201 nisNetgroupTripleValidate(
3203 struct berval *val )
3208 if ( BER_BVISEMPTY( val ) ) {
3209 return LDAP_INVALID_SYNTAX;
3212 p = (char *)val->bv_val;
3213 e = p + val->bv_len;
3215 if ( *p != '(' /*')'*/ ) {
3216 return LDAP_INVALID_SYNTAX;
3219 for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
3223 return LDAP_INVALID_SYNTAX;
3226 } else if ( !AD_CHAR( *p ) ) {
3227 return LDAP_INVALID_SYNTAX;
3231 if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
3232 return LDAP_INVALID_SYNTAX;
3238 return LDAP_INVALID_SYNTAX;
3241 return LDAP_SUCCESS;
3245 bootParameterValidate(
3247 struct berval *val )
3251 if ( BER_BVISEMPTY( val ) ) {
3252 return LDAP_INVALID_SYNTAX;
3255 p = (char *)val->bv_val;
3256 e = p + val->bv_len;
3259 for (; ( p < e ) && ( *p != '=' ); p++ ) {
3260 if ( !AD_CHAR( *p ) ) {
3261 return LDAP_INVALID_SYNTAX;
3266 return LDAP_INVALID_SYNTAX;
3270 for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
3271 if ( !AD_CHAR( *p ) ) {
3272 return LDAP_INVALID_SYNTAX;
3277 return LDAP_INVALID_SYNTAX;
3281 for ( p++; p < e; p++ ) {
3282 if ( !SLAP_PRINTABLE( *p ) ) {
3283 return LDAP_INVALID_SYNTAX;
3287 return LDAP_SUCCESS;
3291 firstComponentNormalize(
3296 struct berval *normalized,
3303 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
3304 ber_dupbv_x( normalized, val, ctx );
3305 return LDAP_SUCCESS;
3308 if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3310 if( val->bv_val[0] != '(' /*')'*/ &&
3311 val->bv_val[0] != '{' /*'}'*/ )
3313 return LDAP_INVALID_SYNTAX;
3316 /* trim leading white space */
3318 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
3324 /* grab next word */
3325 comp.bv_val = &val->bv_val[len];
3326 len = val->bv_len - len;
3327 for( comp.bv_len = 0;
3328 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
3334 if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
3335 rc = numericoidValidate( NULL, &comp );
3336 } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
3337 rc = integerValidate( NULL, &comp );
3339 rc = LDAP_INVALID_SYNTAX;
3343 if( rc == LDAP_SUCCESS ) {
3344 ber_dupbv_x( normalized, &comp, ctx );
3351 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
3352 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
3354 static slap_syntax_defs_rec syntax_defs[] = {
3355 {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
3356 X_BINARY X_NOT_H_R ")",
3357 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL},
3358 {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
3360 {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
3362 {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
3364 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3365 {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
3367 SLAP_SYNTAX_BER, berValidate, NULL},
3368 {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
3369 0, bitStringValidate, NULL },
3370 {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
3371 0, booleanValidate, NULL},
3372 {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
3373 X_BINARY X_NOT_H_R ")",
3374 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, certificateValidate, NULL},
3375 {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
3376 X_BINARY X_NOT_H_R ")",
3377 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3378 {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
3379 X_BINARY X_NOT_H_R ")",
3380 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, sequenceValidate, NULL},
3381 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
3382 0, countryStringValidate, NULL},
3383 {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
3384 0, dnValidate, dnPretty},
3385 {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
3386 0, rdnValidate, rdnPretty},
3387 #ifdef LDAP_COMP_MATCH
3388 {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
3389 0, allComponentsValidate, NULL},
3390 {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
3391 0, componentFilterValidate, NULL},
3393 {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
3395 {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
3396 0, deliveryMethodValidate, NULL},
3397 {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
3398 0, UTF8StringValidate, NULL},
3399 {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
3401 {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
3403 {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
3405 {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
3407 {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
3409 {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
3410 0, printablesStringValidate, NULL},
3411 {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
3412 SLAP_SYNTAX_BLOB, NULL, NULL},
3413 {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
3414 0, generalizedTimeValidate, NULL},
3415 {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
3417 {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
3418 0, IA5StringValidate, NULL},
3419 {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
3420 0, integerValidate, NULL},
3421 {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
3422 SLAP_SYNTAX_BLOB, blobValidate, NULL},
3423 {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
3425 {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
3427 {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
3429 {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
3431 {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
3433 {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
3434 0, nameUIDValidate, nameUIDPretty },
3435 {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
3437 {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
3438 0, numericStringValidate, NULL},
3439 {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
3441 {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
3442 0, numericoidValidate, NULL},
3443 {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
3444 0, IA5StringValidate, NULL},
3445 {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
3446 0, blobValidate, NULL},
3447 {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
3448 0, UTF8StringValidate, NULL},
3449 {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
3451 {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
3453 {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
3454 0, printableStringValidate, NULL},
3455 {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
3456 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
3457 0, subtreeSpecificationValidate, NULL},
3458 {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
3459 X_BINARY X_NOT_H_R ")",
3460 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, berValidate, NULL},
3461 {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
3462 0, printableStringValidate, NULL},
3463 {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
3465 {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
3466 0, printablesStringValidate, NULL},
3467 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3468 {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
3469 0, utcTimeValidate, NULL},
3471 {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
3473 {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
3475 {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
3477 {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
3479 {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
3482 /* RFC 2307 NIS Syntaxes */
3483 {"( 1.3.6.1.1.1.0.0 DESC 'RFC2307 NIS Netgroup Triple' )",
3484 0, nisNetgroupTripleValidate, NULL},
3485 {"( 1.3.6.1.1.1.0.1 DESC 'RFC2307 Boot Parameter' )",
3486 0, bootParameterValidate, NULL},
3488 /* From PKIX *//* This OID is not published yet. */
3489 {"( 1.2.826.0.1.3344810.7.1 DESC 'Certificate Serial Number and Issuer' )",
3491 serialNumberAndIssuerValidate,
3492 serialNumberAndIssuerPretty},
3494 #ifdef SLAPD_AUTHPASSWD
3495 /* needs updating */
3496 {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
3497 SLAP_SYNTAX_HIDE, NULL, NULL},
3500 {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
3501 0, UUIDValidate, UUIDPretty},
3503 {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
3504 SLAP_SYNTAX_HIDE, csnValidate, NULL},
3506 /* OpenLDAP Void Syntax */
3507 {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
3508 SLAP_SYNTAX_HIDE, inValidate, NULL},
3510 #ifdef SLAP_AUTHZ_SYNTAX
3511 /* FIXME: OID is unused, but not registered yet */
3512 {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
3513 SLAP_SYNTAX_HIDE, authzValidate, authzPretty},
3514 #endif /* SLAP_AUTHZ_SYNTAX */
3516 {NULL, 0, NULL, NULL}
3519 char *certificateExactMatchSyntaxes[] = {
3520 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
3523 #ifdef LDAP_COMP_MATCH
3524 char *componentFilterMatchSyntaxes[] = {
3525 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
3529 char *directoryStringSyntaxes[] = {
3530 "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
3533 char *integerFirstComponentMatchSyntaxes[] = {
3534 "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
3535 "1.3.6.1.4.1.1466.115.121.1.17" /* ditStructureRuleDescription */,
3538 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
3539 "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
3540 "1.3.6.1.4.1.1466.115.121.1.3" /* attributeTypeDescription */,
3541 "1.3.6.1.4.1.1466.115.121.1.16" /* ditContentRuleDescription */,
3542 "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
3543 "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
3544 "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
3545 "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
3546 "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
3551 * Other matching rules in X.520 that we do not use (yet):
3553 * 2.5.13.25 uTCTimeMatch
3554 * 2.5.13.26 uTCTimeOrderingMatch
3555 * 2.5.13.31* directoryStringFirstComponentMatch
3556 * 2.5.13.32* wordMatch
3557 * 2.5.13.33* keywordMatch
3558 * 2.5.13.36 certificatePairExactMatch
3559 * 2.5.13.37 certificatePairMatch
3560 * 2.5.13.38 certificateListExactMatch
3561 * 2.5.13.39 certificateListMatch
3562 * 2.5.13.40 algorithmIdentifierMatch
3563 * 2.5.13.41* storedPrefixMatch
3564 * 2.5.13.42 attributeCertificateMatch
3565 * 2.5.13.43 readerAndKeyIDMatch
3566 * 2.5.13.44 attributeIntegrityMatch
3568 * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
3570 static slap_mrule_defs_rec mrule_defs[] = {
3572 * EQUALITY matching rules must be listed after associated APPROX
3573 * matching rules. So, we list all APPROX matching rules first.
3575 {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
3576 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3577 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3578 NULL, NULL, directoryStringApproxMatch,
3579 directoryStringApproxIndexer, directoryStringApproxFilter,
3582 {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
3583 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3584 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
3585 NULL, NULL, IA5StringApproxMatch,
3586 IA5StringApproxIndexer, IA5StringApproxFilter,
3590 * Other matching rules
3593 {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
3594 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3595 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3596 NULL, NULL, octetStringMatch,
3597 octetStringIndexer, octetStringFilter,
3600 {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
3601 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3602 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3603 NULL, dnNormalize, dnMatch,
3604 octetStringIndexer, octetStringFilter,
3607 {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
3608 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3609 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3610 NULL, dnNormalize, dnRelativeMatch,
3614 {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
3615 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3616 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3617 NULL, dnNormalize, dnRelativeMatch,
3621 {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
3622 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3623 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3624 NULL, dnNormalize, dnRelativeMatch,
3628 {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
3629 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
3630 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
3631 NULL, dnNormalize, dnRelativeMatch,
3635 {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
3636 "SYNTAX 1.2.36.79672281.1.5.0 )",
3637 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3638 NULL, rdnNormalize, rdnMatch,
3639 octetStringIndexer, octetStringFilter,
3642 #ifdef LDAP_COMP_MATCH
3643 {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
3644 "SYNTAX 1.2.36.79672281.1.5.2 )",
3645 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
3646 NULL, NULL , componentFilterMatch,
3647 octetStringIndexer, octetStringFilter,
3650 {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
3651 "SYNTAX 1.2.36.79672281.1.5.3 )",
3652 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
3653 NULL, NULL , allComponentsMatch,
3654 octetStringIndexer, octetStringFilter,
3657 {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
3658 "SYNTAX 1.2.36.79672281.1.5.3 )",
3659 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
3660 NULL, NULL , directoryComponentsMatch,
3661 octetStringIndexer, octetStringFilter,
3665 {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
3666 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3667 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3668 NULL, UTF8StringNormalize, octetStringMatch,
3669 octetStringIndexer, octetStringFilter,
3670 directoryStringApproxMatchOID },
3672 {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
3673 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3674 SLAP_MR_ORDERING, directoryStringSyntaxes,
3675 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3677 "caseIgnoreMatch" },
3679 {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
3680 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3681 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3682 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
3683 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3684 "caseIgnoreMatch" },
3686 {"( 2.5.13.5 NAME 'caseExactMatch' "
3687 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3688 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
3689 NULL, UTF8StringNormalize, octetStringMatch,
3690 octetStringIndexer, octetStringFilter,
3691 directoryStringApproxMatchOID },
3693 {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
3694 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
3695 SLAP_MR_ORDERING, directoryStringSyntaxes,
3696 NULL, UTF8StringNormalize, octetStringOrderingMatch,
3700 {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
3701 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3702 SLAP_MR_SUBSTR, directoryStringSyntaxes,
3703 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
3704 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3707 {"( 2.5.13.8 NAME 'numericStringMatch' "
3708 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3709 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3710 NULL, numericStringNormalize, octetStringMatch,
3711 octetStringIndexer, octetStringFilter,
3714 {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
3715 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
3716 SLAP_MR_ORDERING, NULL,
3717 NULL, numericStringNormalize, octetStringOrderingMatch,
3719 "numericStringMatch" },
3721 {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
3722 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3723 SLAP_MR_SUBSTR, NULL,
3724 NULL, numericStringNormalize, octetStringSubstringsMatch,
3725 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3726 "numericStringMatch" },
3728 {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
3729 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
3730 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3731 NULL, NULL, NULL, NULL, NULL, NULL },
3733 {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
3734 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3735 SLAP_MR_SUBSTR, NULL,
3736 NULL, NULL, NULL, NULL, NULL,
3737 "caseIgnoreListMatch" },
3739 {"( 2.5.13.13 NAME 'booleanMatch' "
3740 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
3741 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3742 NULL, NULL, booleanMatch,
3743 octetStringIndexer, octetStringFilter,
3746 {"( 2.5.13.14 NAME 'integerMatch' "
3747 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3748 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3749 NULL, NULL, integerMatch,
3750 octetStringIndexer, octetStringFilter,
3753 {"( 2.5.13.15 NAME 'integerOrderingMatch' "
3754 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3755 SLAP_MR_ORDERING, NULL,
3756 NULL, NULL, integerMatch,
3760 {"( 2.5.13.16 NAME 'bitStringMatch' "
3761 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
3762 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3763 NULL, NULL, octetStringMatch,
3764 octetStringIndexer, octetStringFilter,
3767 {"( 2.5.13.17 NAME 'octetStringMatch' "
3768 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3769 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3770 NULL, NULL, octetStringMatch,
3771 octetStringIndexer, octetStringFilter,
3774 {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
3775 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3776 SLAP_MR_ORDERING, NULL,
3777 NULL, NULL, octetStringOrderingMatch,
3779 "octetStringMatch" },
3781 {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
3782 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3783 SLAP_MR_SUBSTR, NULL,
3784 NULL, NULL, octetStringSubstringsMatch,
3785 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3786 "octetStringMatch" },
3788 {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
3789 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
3790 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3792 telephoneNumberNormalize, octetStringMatch,
3793 octetStringIndexer, octetStringFilter,
3796 {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
3797 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
3798 SLAP_MR_SUBSTR, NULL,
3799 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
3800 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3801 "telephoneNumberMatch" },
3803 {"( 2.5.13.22 NAME 'presentationAddressMatch' "
3804 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
3805 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3806 NULL, NULL, NULL, NULL, NULL, NULL },
3808 {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
3809 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
3810 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3811 NULL, uniqueMemberNormalize, uniqueMemberMatch,
3812 uniqueMemberIndexer, uniqueMemberFilter,
3815 {"( 2.5.13.24 NAME 'protocolInformationMatch' "
3816 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
3817 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3818 NULL, NULL, NULL, NULL, NULL, NULL },
3820 {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
3821 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3822 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
3823 NULL, generalizedTimeNormalize, octetStringMatch,
3824 generalizedTimeIndexer, generalizedTimeFilter,
3827 {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
3828 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
3829 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
3830 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
3832 "generalizedTimeMatch" },
3834 {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
3835 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3836 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3837 integerFirstComponentMatchSyntaxes,
3838 NULL, firstComponentNormalize, integerMatch,
3839 octetStringIndexer, octetStringFilter,
3842 {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
3843 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
3844 SLAP_MR_EQUALITY | SLAP_MR_EXT,
3845 objectIdentifierFirstComponentMatchSyntaxes,
3846 NULL, firstComponentNormalize, octetStringMatch,
3847 octetStringIndexer, octetStringFilter,
3850 {"( 2.5.13.34 NAME 'certificateExactMatch' "
3851 "SYNTAX 1.2.826.0.1.3344810.7.1 )",
3852 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
3854 NULL, certificateExactNormalize, octetStringMatch,
3855 octetStringIndexer, octetStringFilter,
3857 NULL, NULL, NULL, NULL, NULL,
3861 {"( 2.5.13.35 NAME 'certificateMatch' "
3862 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.8 )",
3863 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3865 NULL, NULL, octetStringMatch,
3866 octetStringIndexer, octetStringFilter,
3868 NULL, NULL, NULL, NULL, NULL,
3872 {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
3873 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3874 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3875 NULL, IA5StringNormalize, octetStringMatch,
3876 octetStringIndexer, octetStringFilter,
3877 IA5StringApproxMatchOID },
3879 {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
3880 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3881 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
3882 NULL, IA5StringNormalize, octetStringMatch,
3883 octetStringIndexer, octetStringFilter,
3884 IA5StringApproxMatchOID },
3886 {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
3887 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3888 SLAP_MR_SUBSTR, NULL,
3889 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
3890 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3891 "caseIgnoreIA5Match" },
3893 {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
3894 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
3895 SLAP_MR_SUBSTR, NULL,
3896 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
3897 octetStringSubstringsIndexer, octetStringSubstringsFilter,
3898 "caseExactIA5Match" },
3900 #ifdef SLAPD_AUTHPASSWD
3901 /* needs updating */
3902 {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
3903 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
3904 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3905 NULL, NULL, authPasswordMatch,
3910 {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
3911 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3913 NULL, NULL, integerBitAndMatch,
3917 {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
3918 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
3920 NULL, NULL, integerBitOrMatch,
3924 {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
3925 "SYNTAX 1.3.6.1.1.16.1 )",
3926 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
3927 NULL, UUIDNormalize, octetStringMatch,
3928 octetStringIndexer, octetStringFilter,
3931 {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
3932 "SYNTAX 1.3.6.1.1.16.1 )",
3933 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
3934 NULL, UUIDNormalize, octetStringOrderingMatch,
3935 octetStringIndexer, octetStringFilter,
3938 {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
3939 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
3940 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
3941 NULL, NULL, csnMatch,
3942 csnIndexer, csnFilter,
3945 {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
3946 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
3947 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
3948 NULL, NULL, csnOrderingMatch,
3952 #ifdef SLAP_AUTHZ_SYNTAX
3953 /* FIXME: OID is unused, but not registered yet */
3954 {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
3955 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
3956 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
3957 NULL, authzNormalize, authzMatch,
3960 #endif /* SLAP_AUTHZ_SYNTAX */
3962 {NULL, SLAP_MR_NONE, NULL,
3963 NULL, NULL, NULL, NULL, NULL,
3968 slap_schema_init( void )
3973 /* we should only be called once (from main) */
3974 assert( schema_init_done == 0 );
3976 for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
3977 res = register_syntax( &syntax_defs[i] );
3980 fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
3981 syntax_defs[i].sd_desc );
3986 for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
3987 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
3988 mrule_defs[i].mrd_compat_syntaxes == NULL )
3991 "slap_schema_init: Ignoring unusable matching rule %s\n",
3992 mrule_defs[i].mrd_desc );
3996 res = register_matching_rule( &mrule_defs[i] );
4000 "slap_schema_init: Error registering matching rule %s\n",
4001 mrule_defs[i].mrd_desc );
4006 res = slap_schema_load();
4007 schema_init_done = 1;
4012 schema_destroy( void )
4021 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
4022 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );