X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=servers%2Fslapd%2Fschema_init.c;h=080bd6a7add89b4e5a645c9ed8efa091d455e3c8;hb=c6b5abbfd20567116846ebc38f0005c429284c98;hp=24ac340b3a1150dd546823f3afaa7e24242e7a57;hpb=ff5b4d6c21c0183f80af4c56d1518f90d5c3866f;p=openldap diff --git a/servers/slapd/schema_init.c b/servers/slapd/schema_init.c index 24ac340b3a..080bd6a7ad 100644 --- a/servers/slapd/schema_init.c +++ b/servers/slapd/schema_init.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2008 The OpenLDAP Foundation. + * Copyright 1998-2012 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -14,6 +14,78 @@ * . */ +/* + * Syntaxes - implementation notes: + * + * Validate function(syntax, value): + * Called before the other functions here to check if the value + * is valid according to the syntax. + * + * Pretty function(syntax, input value, output prettified...): + * If it exists, maps different notations of the same value to a + * unique representation which can be stored in the directory and + * possibly be passed to the Match/Indexer/Filter() functions. + * + * E.g. DN "2.5.4.3 = foo\,bar, o = BAZ" -> "cn=foo\2Cbar,o=BAZ", + * but unlike DN normalization, "BAZ" is not mapped to "baz". + */ + +/* + * Matching rules - implementation notes: + * + * Matching rules match an attribute value (often from the directory) + * against an asserted value (e.g. from a filter). + * + * Invoked with validated and commonly pretty/normalized arguments, thus + * a number of matching rules can simply use the octetString functions. + * + * Normalize function(...input value, output normalized...): + * If it exists, maps matching values to a unique representation + * which is passed to the Match/Indexer/Filter() functions. + * + * Different matching rules can normalize values of the same syntax + * differently. E.g. caseIgnore rules normalize to lowercase, + * caseExact rules do not. + * + * Match function(*output matchp, ...value, asserted value): + * On success, set *matchp. 0 means match. For ORDERING/most EQUALITY, + * less/greater than 0 means value less/greater than asserted. However: + * + * In extensible match filters, ORDERING rules match if valueentry ID set} mapping, for the attribute. + * + * A search can look up the DN/scope and asserted values in the + * indexes, if any, to narrow down the number of entires to check + * against the search criteria. + * + * Filter function(...asserted value, *output keysp,...): + * Generates index key(s) for the asserted value, to be looked up in + * the index from the Indexer function. *keysp is an array because + * substring matching rules can generate multiple lookup keys. + * + * Index keys: + * A key is usually a hash of match type, attribute value and schema + * info, because one index can contain keys for many filtering types. + * + * Some indexes instead have EQUALITY keys ordered so that if + * key(val1) < key(val2), then val1 < val2 by the ORDERING rule. + * That way the ORDERING rule can use the EQUALITY index. + * + * Substring indexing: + * This chops the attribute values up in small chunks and indexes all + * possible chunks of certain sizes. Substring filtering looks up + * SOME of the asserted value's chunks, and the caller uses the + * intersection of the resulting entry ID sets. + * See the index_substr_* keywords in slapd.conf(5). + */ + #include "portable.h" #include @@ -57,6 +129,32 @@ #define authzMatch octetStringMatch +/* X.509 PMI ldapSyntaxes */ +/* FIXME: need to create temporary OIDs under OpenLDAP's arc; + * these are currently hijacked + * + * 1.3.6.1.4.1.4203.666 OpenLDAP + * 1.3.6.1.4.1.4203.666.11 self-contained works + * 1.3.6.1.4.1.4203.666.11.10 X.509 PMI + * 1.3.6.1.4.1.4203.666.11.10.2 X.509 PMI ldapSyntaxes + * 1.3.6.1.4.1.4203.666.11.10.2.1 AttributeCertificate (supported) + * 1.3.6.1.4.1.4203.666.11.10.2.2 AttributeCertificateExactAssertion (supported) + * 1.3.6.1.4.1.4203.666.11.10.2.3 AttributeCertificateAssertion (not supported) + * 1.3.6.1.4.1.4203.666.11.10.2.4 AttCertPath (X-SUBST'ed right now in pmi.schema) + * 1.3.6.1.4.1.4203.666.11.10.2.5 PolicySyntax (X-SUBST'ed right now in pmi.schema) + * 1.3.6.1.4.1.4203.666.11.10.2.6 RoleSyntax (X-SUBST'ed right now in pmi.schema) + */ +#if 0 /* from (expired) */ +#define attributeCertificateSyntaxOID "1.2.826.0.1.3344810.7.5" +#define attributeCertificateExactAssertionSyntaxOID "1.2.826.0.1.3344810.7.6" +#define attributeCertificateAssertionSyntaxOID "1.2.826.0.1.3344810.7.7" +#else /* from OpenLDAP's experimental oid arc */ +#define X509_PMI_SyntaxOID "1.3.6.1.4.1.4203.666.11.10.2" +#define attributeCertificateSyntaxOID X509_PMI_SyntaxOID ".1" +#define attributeCertificateExactAssertionSyntaxOID X509_PMI_SyntaxOID ".2" +#define attributeCertificateAssertionSyntaxOID X509_PMI_SyntaxOID ".3" +#endif + unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT; unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT; unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT; @@ -66,6 +164,7 @@ unsigned int index_intlen = SLAP_INDEX_INTLEN_DEFAULT; unsigned int index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN( SLAP_INDEX_INTLEN_DEFAULT ); +ldap_pvt_thread_mutex_t ad_index_mutex; ldap_pvt_thread_mutex_t ad_undef_mutex; ldap_pvt_thread_mutex_t oc_undef_mutex; @@ -130,8 +229,8 @@ enum { enum { SLAP_X509_OPT_C_VERSION = SLAP_X509_OPTION + 0, - SLAP_X509_OPT_C_ISSUERUNIQUEID = SLAP_X509_OPTION + 1, - SLAP_X509_OPT_C_SUBJECTUNIQUEID = SLAP_X509_OPTION + 2, + SLAP_X509_OPT_C_ISSUERUNIQUEID = LBER_CLASS_CONTEXT + 1, + SLAP_X509_OPT_C_SUBJECTUNIQUEID = LBER_CLASS_CONTEXT + 2, SLAP_X509_OPT_C_EXTENSIONS = SLAP_X509_OPTION + 3 }; @@ -139,6 +238,40 @@ enum { SLAP_X509_OPT_CL_CRLEXTENSIONS = SLAP_X509_OPTION + 0 }; +/* +GeneralName ::= CHOICE { + otherName [0] INSTANCE OF OTHER-NAME, + rfc822Name [1] IA5String, + dNSName [2] IA5String, + x400Address [3] ORAddress, + directoryName [4] Name, + ediPartyName [5] EDIPartyName, + uniformResourceIdentifier [6] IA5String, + iPAddress [7] OCTET STRING, + registeredID [8] OBJECT IDENTIFIER } +*/ +enum { + SLAP_X509_GN_OTHERNAME = SLAP_X509_OPTION + 0, + SLAP_X509_GN_RFC822NAME = SLAP_X509_OPTION + 1, + SLAP_X509_GN_DNSNAME = SLAP_X509_OPTION + 2, + SLAP_X509_GN_X400ADDRESS = SLAP_X509_OPTION + 3, + SLAP_X509_GN_DIRECTORYNAME = SLAP_X509_OPTION + 4, + SLAP_X509_GN_EDIPARTYNAME = SLAP_X509_OPTION + 5, + SLAP_X509_GN_URI = SLAP_X509_OPTION + 6, + SLAP_X509_GN_IPADDRESS = SLAP_X509_OPTION + 7, + SLAP_X509_GN_REGISTEREDID = SLAP_X509_OPTION + 8 +}; + +/* X.509 PMI related stuff */ +enum { + SLAP_X509AC_V1 = 0, + SLAP_X509AC_V2 = 1 +}; + +enum { + SLAP_X509AC_ISSUER = SLAP_X509_OPTION + 0 +}; + /* X.509 certificate validation */ static int certificateValidate( Syntax *syntax, struct berval *in ) @@ -213,18 +346,25 @@ certificateValidate( Syntax *syntax, struct berval *in ) } /* X.509 certificate list validation */ +static int +checkTime( struct berval *in, struct berval *out ); + static int certificateListValidate( Syntax *syntax, struct berval *in ) { BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; ber_tag_t tag; - ber_len_t len; + ber_len_t len, wrapper_len; + char *wrapper_start; + int wrapper_ok = 0; ber_int_t version = SLAP_X509_V1; + struct berval bvdn, bvtu; ber_init2( ber, in, LBER_USE_DER ); - tag = ber_skip_tag( ber, &len ); /* Signed wrapper */ + tag = ber_skip_tag( ber, &wrapper_len ); /* Signed wrapper */ if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + wrapper_start = ber->ber_ptr; tag = ber_skip_tag( ber, &len ); /* Sequence */ if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; tag = ber_peek_tag( ber, &len ); @@ -237,12 +377,18 @@ certificateListValidate( Syntax *syntax, struct berval *in ) tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */ if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; ber_skip_data( ber, len ); - tag = ber_skip_tag( ber, &len ); /* Issuer DN */ + tag = ber_peek_tag( ber, &len ); /* Issuer DN */ if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + len = ber_ptrlen( ber ); + bvdn.bv_val = in->bv_val + len; + bvdn.bv_len = in->bv_len - len; + tag = ber_skip_tag( ber, &len ); ber_skip_data( ber, len ); tag = ber_skip_tag( ber, &len ); /* thisUpdate */ /* Time is a CHOICE { UTCTime, GeneralizedTime } */ if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX; + bvtu.bv_val = (char *)ber->ber_ptr; + bvtu.bv_len = len; ber_skip_data( ber, len ); /* Optional nextUpdate */ tag = ber_skip_tag( ber, &len ); @@ -253,16 +399,20 @@ certificateListValidate( Syntax *syntax, struct berval *in ) /* revokedCertificates - Sequence of Sequence, Optional */ if ( tag == LBER_SEQUENCE ) { ber_len_t seqlen; - if ( ber_peek_tag( ber, &seqlen ) == LBER_SEQUENCE ) { - /* Should NOT be empty */ - ber_skip_data( ber, len ); + ber_tag_t stag; + stag = ber_peek_tag( ber, &seqlen ); + if ( stag == LBER_SEQUENCE || !len ) { + /* RFC5280 requires non-empty, but X.509(2005) allows empty. */ + if ( len ) + ber_skip_data( ber, len ); tag = ber_skip_tag( ber, &len ); } } - /* Optional Extensions */ + /* Optional Extensions - Sequence of Sequence */ if ( tag == SLAP_X509_OPT_CL_CRLEXTENSIONS ) { /* ? */ + ber_len_t seqlen; if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX; - tag = ber_skip_tag( ber, &len ); + tag = ber_peek_tag( ber, &seqlen ); if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; ber_skip_data( ber, len ); tag = ber_skip_tag( ber, &len ); @@ -274,9 +424,127 @@ certificateListValidate( Syntax *syntax, struct berval *in ) /* Signature */ if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX; ber_skip_data( ber, len ); + if ( ber->ber_ptr == wrapper_start + wrapper_len ) wrapper_ok = 1; tag = ber_skip_tag( ber, &len ); /* Must be at end now */ - if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX; + /* NOTE: OpenSSL tolerates CL with garbage past the end */ + if ( len || tag != LBER_DEFAULT ) { + struct berval issuer_dn = BER_BVNULL, thisUpdate; + char tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1]; + int rc; + + if ( ! wrapper_ok ) { + return LDAP_INVALID_SYNTAX; + } + + rc = dnX509normalize( &bvdn, &issuer_dn ); + if ( rc != LDAP_SUCCESS ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + + thisUpdate.bv_val = tubuf; + thisUpdate.bv_len = sizeof(tubuf); + if ( checkTime( &bvtu, &thisUpdate ) ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + + Debug( LDAP_DEBUG_ANY, + "certificateListValidate issuer=\"%s\", thisUpdate=%s: extra cruft past end of certificateList\n", + issuer_dn.bv_val, thisUpdate.bv_val, 0 ); + +done:; + if ( ! BER_BVISNULL( &issuer_dn ) ) { + ber_memfree( issuer_dn.bv_val ); + } + + return rc; + } + + return LDAP_SUCCESS; +} + +/* X.509 PMI Attribute Certificate Validate */ +static int +attributeCertificateValidate( Syntax *syntax, struct berval *in ) +{ + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + ber_tag_t tag; + ber_len_t len; + ber_int_t version; + int cont = 0; + + ber_init2( ber, in, LBER_USE_DER ); + + tag = ber_skip_tag( ber, &len ); /* Signed wrapper */ + if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + + tag = ber_skip_tag( ber, &len ); /* Sequence */ + if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + + tag = ber_peek_tag( ber, &len ); /* Version */ + if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX; + tag = ber_get_int( ber, &version ); /* X.509 only allows v2 */ + if ( version != SLAP_X509AC_V2 ) return LDAP_INVALID_SYNTAX; + + tag = ber_skip_tag( ber, &len ); /* Holder */ + if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + ber_skip_data( ber, len ); + + tag = ber_skip_tag( ber, &len ); /* Issuer */ + if ( tag != SLAP_X509AC_ISSUER ) return LDAP_INVALID_SYNTAX; + ber_skip_data( ber, len ); + + tag = ber_skip_tag( ber, &len ); /* Signature */ + if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + ber_skip_data( ber, len ); + + tag = ber_skip_tag( ber, &len ); /* Serial number */ + if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX; + ber_skip_data( ber, len ); + + tag = ber_skip_tag( ber, &len ); /* AttCertValidityPeriod */ + if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + ber_skip_data( ber, len ); + + tag = ber_skip_tag( ber, &len ); /* Attributes */ + if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + ber_skip_data( ber, len ); + + tag = ber_peek_tag( ber, &len ); + + if ( tag == LBER_BITSTRING ) { /* issuerUniqueID */ + tag = ber_skip_tag( ber, &len ); + ber_skip_data( ber, len ); + tag = ber_peek_tag( ber, &len ); + } + + if ( tag == LBER_SEQUENCE ) { /* extensions or signatureAlgorithm */ + tag = ber_skip_tag( ber, &len ); + ber_skip_data( ber, len ); + cont++; + tag = ber_peek_tag( ber, &len ); + } + + if ( tag == LBER_SEQUENCE ) { /* signatureAlgorithm */ + tag = ber_skip_tag( ber, &len ); + ber_skip_data( ber, len ); + cont++; + tag = ber_peek_tag( ber, &len ); + } + + if ( tag == LBER_BITSTRING ) { /* Signature */ + tag = ber_skip_tag( ber, &len ); + ber_skip_data( ber, len ); + cont++; + tag = ber_peek_tag( ber, &len ); + } + + /* Must be at end now */ + if ( len != 0 || tag != LBER_DEFAULT || cont < 2 ) return LDAP_INVALID_SYNTAX; + return LDAP_SUCCESS; } @@ -290,13 +558,12 @@ octetStringMatch( void *assertedValue ) { struct berval *asserted = (struct berval *) assertedValue; - int match = value->bv_len - asserted->bv_len; + ber_slen_t d = (ber_slen_t) value->bv_len - (ber_slen_t) asserted->bv_len; - if( match == 0 ) { - match = memcmp( value->bv_val, asserted->bv_val, value->bv_len ); - } + /* For speed, order first by length, then by contents */ + *matchp = d ? (sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1) + : memcmp( value->bv_val, asserted->bv_val, value->bv_len ); - *matchp = match; return LDAP_SUCCESS; } @@ -316,12 +583,20 @@ octetStringOrderingMatch( int match = memcmp( value->bv_val, asserted->bv_val, (v_len < av_len ? v_len : av_len) ); - if( match == 0 ) match = v_len - av_len; + if( match == 0 ) + match = sizeof(v_len) == sizeof(int) + ? (int) v_len - (int) av_len + : v_len < av_len ? -1 : v_len > av_len; + + /* If used in extensible match filter, match if value < asserted */ + if ( flags & SLAP_MR_EXT ) + match = (match >= 0); *matchp = match; return LDAP_SUCCESS; } +/* Initialize HASHcontext from match type and schema info */ static void hashPreset( HASH_CONTEXT *HASHcontext, @@ -341,6 +616,7 @@ hashPreset( return; } +/* Set HASHdigest from HASHcontext and value:len */ static void hashIter( HASH_CONTEXT *HASHcontext, @@ -353,7 +629,7 @@ hashIter( HASH_Final( HASHdigest, &ctx ); } -/* Index generation function */ +/* Index generation function: Attribute values -> index hash keys */ int octetStringIndexer( slap_mask_t use, slap_mask_t flags, @@ -399,7 +675,7 @@ int octetStringIndexer( return LDAP_SUCCESS; } -/* Index generation function */ +/* Index generation function: Asserted value -> index hash key */ int octetStringFilter( slap_mask_t use, slap_mask_t flags, @@ -560,7 +836,7 @@ done: return LDAP_SUCCESS; } -/* Substrings Index generation function */ +/* Substring index generation function: Attribute values -> index hash keys */ static int octetStringSubstringsIndexer( slap_mask_t use, @@ -680,6 +956,7 @@ octetStringSubstringsIndexer( return LDAP_SUCCESS; } +/* Substring index generation function: Assertion value -> index hash keys */ static int octetStringSubstringsFilter ( slap_mask_t use, @@ -962,12 +1239,7 @@ bitStringValidate( ... * - * Note: normalization strips any leading "0"s, unless the - * bit string is exactly "'0'B", so the normalized example, - * in slapd, would result in - * - * 1.3.6.1.4.1.1466.0=#04024869,o=test,c=gb#'101'B - * + * Note: * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to * be escaped except when at the beginning of a value, the * definition of Name and Optional UID appears to be flawed, @@ -991,11 +1263,11 @@ bitStringValidate( * * in fact "com#'1'B" is a valid IA5 string. * - * As a consequence, current slapd code assumes that the - * presence of portions of a BitString at the end of the string - * representation of a NameAndOptionalUID means a BitString - * is expected, and cause an error otherwise. This is quite - * arbitrary, and might change in the future. + * As a consequence, current slapd code takes the presence of + * # at the end of the string representation + * of a NameAndOptionalUID to mean this is indeed a BitString. + * This is quite arbitrary - it has changed the past and might + * change in the future. */ @@ -1066,7 +1338,8 @@ nameUIDPretty( if ( rc == LDAP_SUCCESS ) { ber_dupbv_x( &dnval, val, ctx ); - dnval.bv_len -= uidval.bv_len + 1; + uidval.bv_val--; + dnval.bv_len -= ++uidval.bv_len; dnval.bv_val[dnval.bv_len] = '\0'; } else { @@ -1083,36 +1356,18 @@ nameUIDPretty( } if( !BER_BVISNULL( &uidval ) ) { - int i, c, got1; char *tmp; tmp = slap_sl_realloc( out->bv_val, out->bv_len - + STRLENOF( "#" ) + uidval.bv_len + 1, + + uidval.bv_len + 1, ctx ); if( tmp == NULL ) { ber_memfree_x( out->bv_val, ctx ); return LDAP_OTHER; } out->bv_val = tmp; - out->bv_val[out->bv_len++] = '#'; - out->bv_val[out->bv_len++] = '\''; - - got1 = uidval.bv_len < sizeof("'0'B"); - for( i = 1; i < uidval.bv_len - 2; i++ ) { - c = uidval.bv_val[i]; - switch(c) { - case '0': - if( got1 ) out->bv_val[out->bv_len++] = c; - break; - case '1': - got1 = 1; - out->bv_val[out->bv_len++] = c; - break; - } - } - - out->bv_val[out->bv_len++] = '\''; - out->bv_val[out->bv_len++] = 'B'; + memcpy( out->bv_val + out->bv_len, uidval.bv_val, uidval.bv_len ); + out->bv_len += uidval.bv_len; out->bv_val[out->bv_len] = '\0'; } } @@ -1246,9 +1501,10 @@ uniqueMemberMatch( } if( valueUID.bv_len && assertedUID.bv_len ) { - match = valueUID.bv_len - assertedUID.bv_len; - if ( match ) { - *matchp = match; + ber_slen_t d; + d = (ber_slen_t) valueUID.bv_len - (ber_slen_t) assertedUID.bv_len; + if ( d ) { + *matchp = sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1; return LDAP_SUCCESS; } @@ -1399,7 +1655,7 @@ booleanMatch( { /* simplistic matching allowed by rigid validation */ struct berval *asserted = (struct berval *) assertedValue; - *matchp = value->bv_len != asserted->bv_len; + *matchp = (int) asserted->bv_len - (int) value->bv_len; return LDAP_SUCCESS; } @@ -1543,8 +1799,8 @@ UTF8StringNormalize( void *ctx ) { struct berval tmp, nvalue; - int flags; - int i, wasspace; + int flags, wasspace; + ber_len_t i; assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 ); @@ -1562,8 +1818,9 @@ UTF8StringNormalize( ? LDAP_UTF8_APPROX : 0; val = UTF8bvnormalize( val, &tmp, flags, ctx ); + /* out of memory or syntax error, the former is unlikely */ if( val == NULL ) { - return LDAP_OTHER; + return LDAP_INVALID_SYNTAX; } /* collapse spaces (in place) */ @@ -1596,12 +1853,12 @@ UTF8StringNormalize( } nvalue.bv_val[nvalue.bv_len] = '\0'; - } else { + } else if ( tmp.bv_len ) { /* string of all spaces is treated as one space */ nvalue.bv_val[0] = ' '; nvalue.bv_val[1] = '\0'; nvalue.bv_len = 1; - } + } /* should never be entered with 0-length val */ *normalized = nvalue; return LDAP_SUCCESS; @@ -1619,7 +1876,7 @@ directoryStringSubstringsMatch( int match = 0; SubstringsAssertion *sub = assertedValue; struct berval left = *value; - int i; + ber_len_t i; int priorspace=0; if ( !BER_BVISNULL( &sub->sa_initial ) ) { @@ -1898,7 +2155,11 @@ approxIndexer( len = strlen( c ); if( len < SLAPD_APPROX_WORDLEN ) continue; ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] ); - keycount++; + if( keys[keycount].bv_len ) { + keycount++; + } else { + ch_free( keys[keycount].bv_val ); + } i++; } @@ -2008,7 +2269,7 @@ postalAddressValidate( struct berval *in ) { struct berval bv = *in; - int c; + ber_len_t c; for ( c = 0; c < in->bv_len; c++ ) { if ( in->bv_val[c] == '\\' ) { @@ -2044,7 +2305,7 @@ postalAddressNormalize( void *ctx ) { BerVarray lines = NULL, nlines = NULL; - int l, c; + ber_len_t l, c; int rc = LDAP_SUCCESS; MatchingRule *xmr = NULL; char *p; @@ -2075,13 +2336,18 @@ postalAddressNormalize( } lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val; - normalized->bv_len = l; + normalized->bv_len = c = l; - for ( l = 0; !BER_BVISNULL( &lines[l] ); l++ ) { + for ( l = 0; l <= c; l++ ) { /* NOTE: we directly normalize each line, * without unescaping the values, since the special * values '\24' ('$') and '\5C' ('\') are not affected * by normalization */ + if ( !lines[l].bv_len ) { + nlines[l].bv_len = 0; + nlines[l].bv_val = NULL; + continue; + } rc = UTF8StringNormalize( usage, NULL, xmr, &lines[l], &nlines[l], ctx ); if ( rc != LDAP_SUCCESS ) { rc = LDAP_INVALID_SYNTAX; @@ -2094,14 +2360,13 @@ postalAddressNormalize( normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx ); p = normalized->bv_val; - for ( l = 0; !BER_BVISNULL( &nlines[l] ); l++ ) { - p = lutil_strncopy( p, nlines[l].bv_val, nlines[l].bv_len ); - + for ( l = 0; l <= c ; l++ ) { + p = lutil_strbvcopy( p, &nlines[l] ); *p++ = '$'; } *--p = '\0'; - assert( p - normalized->bv_val == normalized->bv_len ); + assert( p == &normalized->bv_val[normalized->bv_len] ); done:; if ( nlines != NULL ) { @@ -2238,6 +2503,10 @@ integerMatch( if( vsign < 0 ) match = -match; } + /* Ordering rule used in extensible match filter? */ + if ( (flags & SLAP_MR_EXT) && (mr->smr_usage & SLAP_MR_ORDERING) ) + match = (match >= 0); + *matchp = match; return LDAP_SUCCESS; } @@ -2253,11 +2522,11 @@ integerVal2Key( struct berval *tmp, void *ctx ) { - /* index format: - * only if too large: one's complement , + /* Integer index key format, designed for memcmp to collate correctly: + * if too large: one's complement sign*, * two's complement value (sign-extended or chopped as needed), - * however the top bits of first byte - * above is the inverse sign. The next bit is the sign as delimiter. + * however in first byte above, the top + * bits are the inverse sign and next bit is the sign as delimiter. */ ber_slen_t k = index_intlen_strlen; ber_len_t chop = 0; @@ -2292,6 +2561,7 @@ integerVal2Key( assert( chop == 0 ); memset( key->bv_val, neg, k ); /* sign-extend */ } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) { + /* Got exponent -k, or no room for 2 sign bits */ lenp = lenbuf + sizeof(lenbuf); chop = - (ber_len_t) k; do { @@ -2299,7 +2569,7 @@ integerVal2Key( signmask >>= 1; } while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) ); /* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff) - * are 1, and the top n+2 bits of lenp[] are the sign bit. */ + * are 1, and the top n+2 bits of lenp[0] are the sign bit. */ k = (lenbuf + sizeof(lenbuf)) - lenp; if ( k > (ber_slen_t) index_intlen ) k = index_intlen; @@ -2311,7 +2581,7 @@ integerVal2Key( return 0; } -/* Index generation function */ +/* Index generation function: Ordered index */ static int integerIndexer( slap_mask_t use, @@ -2377,7 +2647,7 @@ func_leave: return rc; } -/* Index generation function */ +/* Index generation function: Ordered index */ static int integerFilter( slap_mask_t use, @@ -2693,6 +2963,7 @@ UUIDNormalize( } else { slap_sl_free( normalized->bv_val, ctx ); + BER_BVZERO( normalized ); return LDAP_INVALID_SYNTAX; } @@ -2851,9 +3122,8 @@ static int checkNum( struct berval *in, struct berval *out ) { /* parse serialNumber */ - int neg = 0; + ber_len_t neg = 0, extra = 0; char first = '\0'; - int extra = 0; out->bv_val = in->bv_val; out->bv_len = 0; @@ -2911,7 +3181,7 @@ serialNumberAndIssuerCheck( struct berval *is, void *ctx ) { - int n; + ber_len_t n; if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX; @@ -3059,7 +3329,7 @@ serialNumberAndIssuerCheck( ber_dupbv_x( &ni, is, ctx ); } else { - ber_int_t src, dst; + ber_len_t src, dst; ni.bv_len = is->bv_len - numdquotes; ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx ); @@ -3159,12 +3429,12 @@ serialNumberAndIssuerPretty( p = out->bv_val; p = lutil_strcopy( p, "{ serialNumber " /*}*/ ); - p = lutil_strncopy( p, sn.bv_val, sn.bv_len ); + p = lutil_strbvcopy( p, &sn ); p = lutil_strcopy( p, ", issuer rdnSequence:\"" ); - p = lutil_strncopy( p, ni.bv_val, ni.bv_len ); + p = lutil_strbvcopy( p, &ni ); p = lutil_strcopy( p, /*{*/ "\" }" ); - assert( p - out->bv_val == out->bv_len ); + assert( p == &out->bv_val[out->bv_len] ); done:; Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s> => <%s>\n", @@ -3186,8 +3456,7 @@ slap_bin2hex( unsigned char *ptr, zero = '\0'; char *sptr; int first; - int i; - ber_len_t len, nlen; + ber_len_t i, len, nlen; assert( in != NULL ); assert( !BER_BVISNULL( in ) ); @@ -3240,7 +3509,7 @@ slap_bin2hex( *sptr++ = 'H'; *sptr = '\0'; - assert( sptr - out->bv_val == nlen ); + assert( sptr == &out->bv_val[nlen] ); out->bv_len = nlen; @@ -3297,14 +3566,9 @@ serialNumberAndIssuerNormalize( sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx ); } sn2.bv_len = sn.bv_len; - if ( lutil_str2bin( &sn, &sn2, ctx )) { - rc = LDAP_INVALID_SYNTAX; - goto func_leave; - } - sn3.bv_val = sbuf3; sn3.bv_len = sizeof(sbuf3); - if ( slap_bin2hex( &sn2, &sn3, ctx ) ) { + if ( lutil_str2bin( &sn, &sn2, ctx ) || slap_bin2hex( &sn2, &sn3, ctx ) ) { rc = LDAP_INVALID_SYNTAX; goto func_leave; } @@ -3312,7 +3576,6 @@ serialNumberAndIssuerNormalize( out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" ) + sn3.bv_len + ni.bv_len; out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx ); - if ( out->bv_val == NULL ) { out->bv_len = 0; rc = LDAP_OTHER; @@ -3322,12 +3585,12 @@ serialNumberAndIssuerNormalize( p = out->bv_val; p = lutil_strcopy( p, "{ serialNumber " /*}*/ ); - p = lutil_strncopy( p, sn3.bv_val, sn3.bv_len ); + p = lutil_strbvcopy( p, &sn3 ); p = lutil_strcopy( p, ", issuer rdnSequence:\"" ); - p = lutil_strncopy( p, ni.bv_val, ni.bv_len ); + p = lutil_strbvcopy( p, &ni ); p = lutil_strcopy( p, /*{*/ "\" }" ); - assert( p - out->bv_val == out->bv_len ); + assert( p == &out->bv_val[out->bv_len] ); func_leave: Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n", @@ -3419,9 +3682,9 @@ certificateExactNormalize( p = normalized->bv_val; p = lutil_strcopy( p, "{ serialNumber " /*}*/ ); - p = lutil_strncopy( p, sn2.bv_val, sn2.bv_len ); + p = lutil_strbvcopy( p, &sn2 ); p = lutil_strcopy( p, ", issuer rdnSequence:\"" ); - p = lutil_strncopy( p, issuer_dn.bv_val, issuer_dn.bv_len ); + p = lutil_strbvcopy( p, &issuer_dn ); p = lutil_strcopy( p, /*{*/ "\" }" ); rc = LDAP_SUCCESS; @@ -3440,7 +3703,8 @@ done: static int checkTime( struct berval *in, struct berval *out ) { - int i; + int rc; + ber_len_t i; char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1]; struct berval bv; @@ -3493,12 +3757,15 @@ checkTime( struct berval *in, struct berval *out ) return -1; } - i = generalizedTimeValidate( NULL, &bv ); - if ( i == LDAP_SUCCESS && out != NULL ) { + rc = generalizedTimeValidate( NULL, &bv ); + if ( rc == LDAP_SUCCESS && out != NULL ) { + if ( out->bv_len > bv.bv_len ) { + out->bv_val[ bv.bv_len ] = '\0'; + } out->bv_len = bv.bv_len; } - return i != LDAP_SUCCESS; + return rc != LDAP_SUCCESS; } static int @@ -3645,7 +3912,7 @@ issuerAndThisUpdateCheck( ber_dupbv_x( &ni, is, ctx ); } else { - ber_int_t src, dst; + ber_len_t src, dst; ni.bv_len = is->bv_len - numdquotes; ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx ); @@ -3747,12 +4014,12 @@ issuerAndThisUpdatePretty( p = out->bv_val; p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ ); - p = lutil_strncopy( p, ni.bv_val, ni.bv_len ); + p = lutil_strbvcopy( p, &ni ); p = lutil_strcopy( p, "\", thisUpdate \"" ); - p = lutil_strncopy( p, tu.bv_val, tu.bv_len ); + p = lutil_strbvcopy( p, &tu ); p = lutil_strcopy( p, /*{*/ "\" }" ); - assert( p - out->bv_val == out->bv_len ); + assert( p == &out->bv_val[out->bv_len] ); done:; Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n", @@ -3813,12 +4080,12 @@ issuerAndThisUpdateNormalize( p = out->bv_val; p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ ); - p = lutil_strncopy( p, ni.bv_val, ni.bv_len ); + p = lutil_strbvcopy( p, &ni ); p = lutil_strcopy( p, "\", thisUpdate \"" ); - p = lutil_strncopy( p, tu2.bv_val, tu2.bv_len ); + p = lutil_strbvcopy( p, &tu2 ); p = lutil_strcopy( p, /*{*/ "\" }" ); - assert( p - out->bv_val == out->bv_len ); + assert( p == &out->bv_val[out->bv_len] ); func_leave: Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n", @@ -3908,9 +4175,9 @@ certificateListExactNormalize( p = normalized->bv_val; p = lutil_strcopy( p, "{ issuer rdnSequence:\"" ); - p = lutil_strncopy( p, issuer_dn.bv_val, issuer_dn.bv_len ); + p = lutil_strbvcopy( p, &issuer_dn ); p = lutil_strcopy( p, "\", thisUpdate \"" ); - p = lutil_strncopy( p, thisUpdate.bv_val, thisUpdate.bv_len ); + p = lutil_strbvcopy( p, &thisUpdate ); p = lutil_strcopy( p, /*{*/ "\" }" ); rc = LDAP_SUCCESS; @@ -3924,80 +4191,766 @@ done: return rc; } +/* X.509 PMI serialNumberAndIssuerSerialCheck + +AttributeCertificateExactAssertion ::= SEQUENCE { + serialNumber CertificateSerialNumber, + issuer AttCertIssuer } + +CertificateSerialNumber ::= INTEGER + +AttCertIssuer ::= [0] SEQUENCE { +issuerName GeneralNames OPTIONAL, +baseCertificateID [0] IssuerSerial OPTIONAL, +objectDigestInfo [1] ObjectDigestInfo OPTIONAL } +-- At least one component shall be present + +GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + +GeneralName ::= CHOICE { + otherName [0] INSTANCE OF OTHER-NAME, + rfc822Name [1] IA5String, + dNSName [2] IA5String, + x400Address [3] ORAddress, + directoryName [4] Name, + ediPartyName [5] EDIPartyName, + uniformResourceIdentifier [6] IA5String, + iPAddress [7] OCTET STRING, + registeredID [8] OBJECT IDENTIFIER } + +IssuerSerial ::= SEQUENCE { + issuer GeneralNames, + serial CertificateSerialNumber, + issuerUID UniqueIdentifier OPTIONAL } + +ObjectDigestInfo ::= SEQUENCE { + digestedObjectType ENUMERATED { + publicKey (0), + publicKeyCert (1), + otherObjectTypes (2) }, + otherObjectTypeID OBJECT IDENTIFIER OPTIONAL, + digestAlgorithm AlgorithmIdentifier, + objectDigest BIT STRING } + + * The way I interpret it, an assertion should look like + + { serialNumber 'dd'H, + issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional + baseCertificateID { serial '1d'H, + issuer { directoryName:rdnSequence:"cn=zzz" }, + issuerUID -- optional + }, -- optional + objectDigestInfo { ... } -- optional + } + } + + * with issuerName, baseCertificateID and objectDigestInfo optional, + * at least one present; the way it's currently implemented, it is + + { serialNumber 'dd'H, + issuer { baseCertificateID { serial '1d'H, + issuer { directoryName:rdnSequence:"cn=zzz" } + } + } + } + + * with all the above parts mandatory. + */ static int -hexValidate( - Syntax *syntax, - struct berval *in ) +serialNumberAndIssuerSerialCheck( + struct berval *in, + struct berval *sn, + struct berval *is, + struct berval *i_sn, /* contain serial of baseCertificateID */ + void *ctx ) { - int i; + /* Parse GSER format */ + enum { + HAVE_NONE = 0x0, + HAVE_SN = 0x1, + HAVE_ISSUER = 0x2, + HAVE_ALL = ( HAVE_SN | HAVE_ISSUER ) + } have = HAVE_NONE, have2 = HAVE_NONE; + int numdquotes = 0; + struct berval x = *in; + struct berval ni; - assert( in != NULL ); - assert( !BER_BVISNULL( in ) ); + if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX; - for ( i = 0; i < in->bv_len; i++ ) { - if ( !ASCII_HEX( in->bv_val[ i ] ) ) { - return LDAP_INVALID_SYNTAX; - } - } + /* no old format */ + if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX; - return LDAP_SUCCESS; -} + x.bv_val++; + x.bv_len -= 2; -/* Normalize a SID as used inside a CSN: - * three-digit numeric string */ -static int -hexNormalize( - slap_mask_t usage, - Syntax *syntax, - MatchingRule *mr, - struct berval *val, - struct berval *normalized, - void *ctx ) -{ - int i; + do { - assert( val != NULL ); - assert( normalized != NULL ); + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } - ber_dupbv_x( normalized, val, ctx ); + /* should be at issuer or serialNumber NamedValue */ + if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) { + if ( have & HAVE_ISSUER ) { + return LDAP_INVALID_SYNTAX; + } - for ( i = 0; i < normalized->bv_len; i++ ) { - if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) { - ber_memfree_x( normalized->bv_val, ctx ); - BER_BVZERO( normalized ); - return LDAP_INVALID_SYNTAX; - } + /* parse IssuerSerial */ + x.bv_val += STRLENOF("issuer"); + x.bv_len -= STRLENOF("issuer"); - normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] ); - } + if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; - return LDAP_SUCCESS; -} + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } -static int -sidValidate ( - Syntax *syntax, - struct berval *in ) -{ - assert( in != NULL ); - assert( !BER_BVISNULL( in ) ); + if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; - if ( in->bv_len != 3 ) { - return LDAP_INVALID_SYNTAX; - } + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } - return hexValidate( NULL, in ); -} + if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) { + return LDAP_INVALID_SYNTAX; + } + x.bv_val += STRLENOF("baseCertificateID "); + x.bv_len -= STRLENOF("baseCertificateID "); -/* Normalize a SID as used inside a CSN: - * three-digit numeric string */ -static int -sidNormalize( - slap_mask_t usage, - Syntax *syntax, - MatchingRule *mr, - struct berval *val, - struct berval *normalized, + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } + + if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; + + do { + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } + + /* parse issuer of baseCertificateID */ + if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) { + if ( have2 & HAVE_ISSUER ) { + return LDAP_INVALID_SYNTAX; + } + + x.bv_val += STRLENOF("issuer "); + x.bv_len -= STRLENOF("issuer "); + + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } + + if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; + + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } + + if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) { + return LDAP_INVALID_SYNTAX; + } + x.bv_val += STRLENOF("directoryName:rdnSequence:"); + x.bv_len -= STRLENOF("directoryName:rdnSequence:"); + + if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; + + is->bv_val = x.bv_val; + is->bv_len = 0; + + for ( ; is->bv_len < x.bv_len; ) { + if ( is->bv_val[is->bv_len] != '"' ) { + is->bv_len++; + continue; + } + if ( is->bv_val[is->bv_len + 1] == '"' ) { + /* double dquote */ + is->bv_len += 2; + continue; + } + break; + } + x.bv_val += is->bv_len + 1; + x.bv_len -= is->bv_len + 1; + + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } + + if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; + + have2 |= HAVE_ISSUER; + + } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) { + if ( have2 & HAVE_SN ) { + return LDAP_INVALID_SYNTAX; + } + + x.bv_val += STRLENOF("serial "); + x.bv_len -= STRLENOF("serial "); + + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) { + /* empty */; + } + + if ( checkNum( &x, i_sn ) ) { + return LDAP_INVALID_SYNTAX; + } + + x.bv_val += i_sn->bv_len; + x.bv_len -= i_sn->bv_len; + + have2 |= HAVE_SN; + + } else { + return LDAP_INVALID_SYNTAX; + } + + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } + + if ( have2 == HAVE_ALL ) { + break; + } + + if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; + } while ( 1 ); + + if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; + + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } + + if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; + + have |= HAVE_ISSUER; + + } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) { + if ( have & HAVE_SN ) { + return LDAP_INVALID_SYNTAX; + } + + /* parse serialNumber */ + x.bv_val += STRLENOF("serialNumber"); + x.bv_len -= STRLENOF("serialNumber"); + + if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; + + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } + + if ( checkNum( &x, sn ) ) { + return LDAP_INVALID_SYNTAX; + } + + x.bv_val += sn->bv_len; + x.bv_len -= sn->bv_len; + + have |= HAVE_SN; + + } else { + return LDAP_INVALID_SYNTAX; + } + + /* eat spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } + + if ( have == HAVE_ALL ) { + break; + } + + if ( x.bv_val[0] != ',' ) { + return LDAP_INVALID_SYNTAX; + } + x.bv_val++ ; + x.bv_len--; + } while ( 1 ); + + /* should have no characters left... */ + if( x.bv_len ) return LDAP_INVALID_SYNTAX; + + if ( numdquotes == 0 ) { + ber_dupbv_x( &ni, is, ctx ); + + } else { + ber_len_t src, dst; + + ni.bv_len = is->bv_len - numdquotes; + ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx ); + for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) { + if ( is->bv_val[src] == '"' ) { + src++; + } + ni.bv_val[dst] = is->bv_val[src]; + } + ni.bv_val[dst] = '\0'; + } + + *is = ni; + + /* need to handle double dquotes here */ + return 0; +} + +/* X.509 PMI serialNumberAndIssuerSerialValidate */ +static int +serialNumberAndIssuerSerialValidate( + Syntax *syntax, + struct berval *in ) +{ + int rc; + struct berval sn, i, i_sn; + + Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n", + in->bv_val, 0, 0 ); + + rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL ); + if ( rc ) { + goto done; + } + + /* validate DN -- doesn't handle double dquote */ + rc = dnValidate( NULL, &i ); + if ( rc ) { + rc = LDAP_INVALID_SYNTAX; + } + + if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) { + slap_sl_free( i.bv_val, NULL ); + } + +done:; + Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n", + in->bv_val, rc, 0 ); + + return rc; +} + +/* X.509 PMI serialNumberAndIssuerSerialPretty */ +static int +serialNumberAndIssuerSerialPretty( + Syntax *syntax, + struct berval *in, + struct berval *out, + void *ctx ) +{ + struct berval sn, i, i_sn, ni = BER_BVNULL; + char *p; + int rc; + + assert( in != NULL ); + assert( out != NULL ); + + Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n", + in->bv_val, 0, 0 ); + + rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx ); + if ( rc ) { + goto done; + } + + rc = dnPretty( syntax, &i, &ni, ctx ); + + if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) { + slap_sl_free( i.bv_val, ctx ); + } + + if ( rc ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + + /* make room from sn + "$" */ + out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }") + + sn.bv_len + ni.bv_len + i_sn.bv_len; + out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx ); + + if ( out->bv_val == NULL ) { + out->bv_len = 0; + rc = LDAP_OTHER; + goto done; + } + + p = out->bv_val; + p = lutil_strcopy( p, "{ serialNumber " ); + p = lutil_strbvcopy( p, &sn ); + p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" ); + p = lutil_strbvcopy( p, &ni ); + p = lutil_strcopy( p, "\" }, serial " ); + p = lutil_strbvcopy( p, &i_sn ); + p = lutil_strcopy( p, " } } }" ); + + assert( p == &out->bv_val[out->bv_len] ); + +done:; + Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n", + in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 ); + + slap_sl_free( ni.bv_val, ctx ); + + return rc; +} + +/* X.509 PMI serialNumberAndIssuerSerialNormalize */ +/* + * This routine is called by attributeCertificateExactNormalize + * when attributeCertificateExactNormalize receives a search + * string instead of a attribute certificate. This routine + * checks if the search value is valid and then returns the + * normalized value + */ +static int +serialNumberAndIssuerSerialNormalize( + slap_mask_t usage, + Syntax *syntax, + MatchingRule *mr, + struct berval *in, + struct berval *out, + void *ctx ) +{ + struct berval i, ni = BER_BVNULL, + sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL, + i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL; + char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN], + sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN]; + char *p; + int rc; + + assert( in != NULL ); + assert( out != NULL ); + + Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n", + in->bv_val, 0, 0 ); + + rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx ); + if ( rc ) { + goto func_leave; + } + + rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx ); + + if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) { + slap_sl_free( i.bv_val, ctx ); + } + + if ( rc ) { + rc = LDAP_INVALID_SYNTAX; + goto func_leave; + } + + /* Convert sn to canonical hex */ + sn2.bv_val = sbuf2; + sn2.bv_len = sn.bv_len; + if ( sn.bv_len > sizeof( sbuf2 ) ) { + sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx ); + } + if ( lutil_str2bin( &sn, &sn2, ctx ) ) { + rc = LDAP_INVALID_SYNTAX; + goto func_leave; + } + + /* Convert i_sn to canonical hex */ + i_sn2.bv_val = i_sbuf2; + i_sn2.bv_len = i_sn.bv_len; + if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) { + i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx ); + } + if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) { + rc = LDAP_INVALID_SYNTAX; + goto func_leave; + } + + sn3.bv_val = sbuf3; + sn3.bv_len = sizeof(sbuf3); + if ( slap_bin2hex( &sn2, &sn3, ctx ) ) { + rc = LDAP_INVALID_SYNTAX; + goto func_leave; + } + + i_sn3.bv_val = i_sbuf3; + i_sn3.bv_len = sizeof(i_sbuf3); + if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) { + rc = LDAP_INVALID_SYNTAX; + goto func_leave; + } + + out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }") + + sn3.bv_len + ni.bv_len + i_sn3.bv_len; + out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx ); + + if ( out->bv_val == NULL ) { + out->bv_len = 0; + rc = LDAP_OTHER; + goto func_leave; + } + + p = out->bv_val; + + p = lutil_strcopy( p, "{ serialNumber " ); + p = lutil_strbvcopy( p, &sn3 ); + p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" ); + p = lutil_strbvcopy( p, &ni ); + p = lutil_strcopy( p, "\" }, serial " ); + p = lutil_strbvcopy( p, &i_sn3 ); + p = lutil_strcopy( p, " } } }" ); + + assert( p == &out->bv_val[out->bv_len] ); + +func_leave: + Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n", + in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 ); + + if ( sn2.bv_val != sbuf2 ) { + slap_sl_free( sn2.bv_val, ctx ); + } + + if ( i_sn2.bv_val != i_sbuf2 ) { + slap_sl_free( i_sn2.bv_val, ctx ); + } + + if ( sn3.bv_val != sbuf3 ) { + slap_sl_free( sn3.bv_val, ctx ); + } + + if ( i_sn3.bv_val != i_sbuf3 ) { + slap_sl_free( i_sn3.bv_val, ctx ); + } + + slap_sl_free( ni.bv_val, ctx ); + + return rc; +} + +/* X.509 PMI attributeCertificateExactNormalize */ +static int +attributeCertificateExactNormalize( + slap_mask_t usage, + Syntax *syntax, + MatchingRule *mr, + struct berval *val, + struct berval *normalized, + void *ctx ) +{ + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + ber_tag_t tag; + ber_len_t len; + char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN]; + struct berval sn, i_sn, sn2 = BER_BVNULL, i_sn2 = BER_BVNULL; + struct berval issuer_dn = BER_BVNULL, bvdn; + char *p; + int rc = LDAP_INVALID_SYNTAX; + + if ( BER_BVISEMPTY( val ) ) { + return rc; + } + + if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) { + return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx ); + } + + assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 ); + + ber_init2( ber, val, LBER_USE_DER ); + tag = ber_skip_tag( ber, &len ); /* Signed Sequence */ + tag = ber_skip_tag( ber, &len ); /* Sequence */ + tag = ber_skip_tag( ber, &len ); /* (Mandatory) version; must be v2(1) */ + ber_skip_data( ber, len ); + tag = ber_skip_tag( ber, &len ); /* Holder Sequence */ + ber_skip_data( ber, len ); + + /* Issuer */ + tag = ber_skip_tag( ber, &len ); /* Sequence */ + /* issuerName (GeneralNames sequence; optional)? */ + tag = ber_skip_tag( ber, &len ); /* baseCertificateID (sequence; optional)? */ + tag = ber_skip_tag( ber, &len ); /* GeneralNames (sequence) */ + tag = ber_skip_tag( ber, &len ); /* directoryName (we only accept this form of GeneralName) */ + if ( tag != SLAP_X509_GN_DIRECTORYNAME ) { + return LDAP_INVALID_SYNTAX; + } + tag = ber_peek_tag( ber, &len ); /* sequence of RDN */ + len = ber_ptrlen( ber ); + bvdn.bv_val = val->bv_val + len; + bvdn.bv_len = val->bv_len - len; + rc = dnX509normalize( &bvdn, &issuer_dn ); + if ( rc != LDAP_SUCCESS ) goto done; + + tag = ber_skip_tag( ber, &len ); /* sequence of RDN */ + ber_skip_data( ber, len ); + tag = ber_skip_tag( ber, &len ); /* serial number */ + if ( tag != LBER_INTEGER ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + i_sn.bv_val = (char *)ber->ber_ptr; + i_sn.bv_len = len; + i_sn2.bv_val = issuer_serialbuf; + i_sn2.bv_len = sizeof(issuer_serialbuf); + if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + ber_skip_data( ber, len ); + + /* issuerUID (bitstring; optional)? */ + /* objectDigestInfo (sequence; optional)? */ + + tag = ber_skip_tag( ber, &len ); /* Signature (sequence) */ + ber_skip_data( ber, len ); + tag = ber_skip_tag( ber, &len ); /* serial number */ + if ( tag != LBER_INTEGER ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + sn.bv_val = (char *)ber->ber_ptr; + sn.bv_len = len; + sn2.bv_val = serialbuf; + sn2.bv_len = sizeof(serialbuf); + if ( slap_bin2hex( &sn, &sn2, ctx ) ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + ber_skip_data( ber, len ); + + normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }" ) + + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len; + normalized->bv_val = ch_malloc( normalized->bv_len + 1 ); + + p = normalized->bv_val; + + p = lutil_strcopy( p, "{ serialNumber " ); + p = lutil_strbvcopy( p, &sn2 ); + p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" ); + p = lutil_strbvcopy( p, &issuer_dn ); + p = lutil_strcopy( p, "\" }, serial " ); + p = lutil_strbvcopy( p, &i_sn2 ); + p = lutil_strcopy( p, " } } }" ); + + Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n", + normalized->bv_val, NULL, NULL ); + + rc = LDAP_SUCCESS; + +done: + if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val ); + if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx ); + if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx ); + + return rc; +} + + +static int +hexValidate( + Syntax *syntax, + struct berval *in ) +{ + ber_len_t i; + + assert( in != NULL ); + assert( !BER_BVISNULL( in ) ); + + for ( i = 0; i < in->bv_len; i++ ) { + if ( !ASCII_HEX( in->bv_val[ i ] ) ) { + return LDAP_INVALID_SYNTAX; + } + } + + return LDAP_SUCCESS; +} + +/* Normalize a SID as used inside a CSN: + * three-digit numeric string */ +static int +hexNormalize( + slap_mask_t usage, + Syntax *syntax, + MatchingRule *mr, + struct berval *val, + struct berval *normalized, + void *ctx ) +{ + ber_len_t i; + + assert( val != NULL ); + assert( normalized != NULL ); + + ber_dupbv_x( normalized, val, ctx ); + + for ( i = 0; i < normalized->bv_len; i++ ) { + if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) { + ber_memfree_x( normalized->bv_val, ctx ); + BER_BVZERO( normalized ); + return LDAP_INVALID_SYNTAX; + } + + normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] ); + } + + return LDAP_SUCCESS; +} + +static int +sidValidate ( + Syntax *syntax, + struct berval *in ) +{ + assert( in != NULL ); + assert( !BER_BVISNULL( in ) ); + + if ( in->bv_len != 3 ) { + return LDAP_INVALID_SYNTAX; + } + + return hexValidate( NULL, in ); +} + +/* Normalize a SID as used inside a CSN: + * three-digit numeric string */ +static int +sidNormalize( + slap_mask_t usage, + Syntax *syntax, + MatchingRule *mr, + struct berval *val, + struct berval *normalized, void *ctx ) { if ( val->bv_len != 3 ) { @@ -4045,7 +4998,7 @@ csnSidNormalize( assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 ); ptr = ber_bvchr( val, '#' ); - if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) { + if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { return LDAP_INVALID_SYNTAX; } @@ -4053,7 +5006,7 @@ csnSidNormalize( bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val ); ptr = ber_bvchr( &bv, '#' ); - if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) { + if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { return LDAP_INVALID_SYNTAX; } @@ -4061,7 +5014,7 @@ csnSidNormalize( bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val ); ptr = ber_bvchr( &bv, '#' ); - if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) { + if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { return LDAP_INVALID_SYNTAX; } @@ -4100,7 +5053,7 @@ csnValidate( bv = *in; ptr = ber_bvchr( &bv, '#' ); - if ( ptr == NULL || ptr - bv.bv_val == bv.bv_len ) { + if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) { return LDAP_INVALID_SYNTAX; } @@ -4120,7 +5073,7 @@ csnValidate( bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val ); ptr = ber_bvchr( &bv, '#' ); - if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) { + if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) { return LDAP_INVALID_SYNTAX; } @@ -4138,7 +5091,7 @@ csnValidate( bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val ); ptr = ber_bvchr( &bv, '#' ); - if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) { + if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) { return LDAP_INVALID_SYNTAX; } @@ -4178,7 +5131,7 @@ csnNormalize21( struct berval bv; char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ]; char *ptr; - int i; + ber_len_t i; assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 ); assert( !BER_BVISEMPTY( val ) ); @@ -4186,7 +5139,7 @@ csnNormalize21( gt = *val; ptr = ber_bvchr( >, '#' ); - if ( ptr == NULL || ptr - gt.bv_val == gt.bv_len ) { + if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) { return LDAP_INVALID_SYNTAX; } @@ -4203,7 +5156,7 @@ csnNormalize21( cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val ); ptr = ber_bvchr( &cnt, '#' ); - if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) { + if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { return LDAP_INVALID_SYNTAX; } @@ -4223,7 +5176,7 @@ csnNormalize21( sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val ); ptr = ber_bvchr( &sid, '#' ); - if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) { + if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { return LDAP_INVALID_SYNTAX; } @@ -4248,7 +5201,7 @@ csnNormalize21( ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ], STRLENOF( "SS" ) ); ptr = lutil_strcopy( ptr, ".000000Z#00" ); - ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len ); + ptr = lutil_strbvcopy( ptr, &cnt ); *ptr++ = '#'; *ptr++ = '0'; *ptr++ = '0'; @@ -4261,7 +5214,7 @@ csnNormalize21( } *ptr = '\0'; - assert( ptr - bv.bv_val == bv.bv_len ); + assert( ptr == &bv.bv_val[bv.bv_len] ); if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) { return LDAP_INVALID_SYNTAX; @@ -4286,7 +5239,7 @@ csnNormalize23( struct berval bv; char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ]; char *ptr; - int i; + ber_len_t i; assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 ); assert( !BER_BVISEMPTY( val ) ); @@ -4294,7 +5247,7 @@ csnNormalize23( gt = *val; ptr = ber_bvchr( >, '#' ); - if ( ptr == NULL || ptr - gt.bv_val == gt.bv_len ) { + if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) { return LDAP_INVALID_SYNTAX; } @@ -4307,7 +5260,7 @@ csnNormalize23( cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val ); ptr = ber_bvchr( &cnt, '#' ); - if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) { + if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { return LDAP_INVALID_SYNTAX; } @@ -4320,7 +5273,7 @@ csnNormalize23( sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val ); ptr = ber_bvchr( &sid, '#' ); - if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) { + if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { return LDAP_INVALID_SYNTAX; } @@ -4341,7 +5294,7 @@ csnNormalize23( ptr = bv.bv_val; ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 ); ptr = lutil_strcopy( ptr, ".000000Z#" ); - ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len ); + ptr = lutil_strbvcopy( ptr, &cnt ); *ptr++ = '#'; *ptr++ = '0'; for ( i = 0; i < sid.bv_len; i++ ) { @@ -4353,7 +5306,7 @@ csnNormalize23( } *ptr = '\0'; - assert( ptr - bv.bv_val == bv.bv_len ); + assert( ptr == &bv.bv_val[bv.bv_len] ); if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) { return LDAP_INVALID_SYNTAX; } @@ -4375,7 +5328,7 @@ csnNormalize( { struct berval cnt, sid, mod; char *ptr; - int i; + ber_len_t i; assert( val != NULL ); assert( normalized != NULL ); @@ -4403,7 +5356,7 @@ csnNormalize( } ptr = ber_bvchr( val, '#' ); - if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) { + if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { return LDAP_INVALID_SYNTAX; } @@ -4415,7 +5368,7 @@ csnNormalize( cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val ); ptr = ber_bvchr( &cnt, '#' ); - if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) { + if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { return LDAP_INVALID_SYNTAX; } @@ -4427,7 +5380,7 @@ csnNormalize( sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val ); ptr = ber_bvchr( &sid, '#' ); - if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) { + if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { return LDAP_INVALID_SYNTAX; } @@ -4752,11 +5705,15 @@ generalizedTimeOrderingMatch( (v_len < av_len ? v_len : av_len) - 1 ); if ( match == 0 ) match = v_len - av_len; + /* If used in extensible match filter, match if value < asserted */ + if ( flags & SLAP_MR_EXT ) + match = (match >= 0); + *matchp = match; return LDAP_SUCCESS; } -/* Index generation function */ +/* Index generation function: Ordered index */ int generalizedTimeIndexer( slap_mask_t use, slap_mask_t flags, @@ -4812,7 +5769,7 @@ int generalizedTimeIndexer( return LDAP_SUCCESS; } -/* Index generation function */ +/* Index generation function: Ordered index */ int generalizedTimeFilter( slap_mask_t use, slap_mask_t flags, @@ -5146,9 +6103,9 @@ firstComponentNormalize( } static char *country_gen_syn[] = { - "1.3.6.1.4.1.1466.115.121.1.15", - "1.3.6.1.4.1.1466.115.121.1.26", - "1.3.6.1.4.1.1466.115.121.1.44", + "1.3.6.1.4.1.1466.115.121.1.15", /* Directory String */ + "1.3.6.1.4.1.1466.115.121.1.26", /* IA5 String */ + "1.3.6.1.4.1.1466.115.121.1.44", /* Printable String */ NULL }; @@ -5185,13 +6142,17 @@ static slap_syntax_defs_rec syntax_defs[] = { X_BINARY X_NOT_H_R ")", SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, sequenceValidate, NULL}, + {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' " + X_BINARY X_NOT_H_R ")", + SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, + NULL, attributeCertificateValidate, NULL}, #if 0 /* need to go __after__ printableString */ {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )", 0, "1.3.6.1.4.1.1466.115.121.1.44", countryStringValidate, NULL}, #endif {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )", - 0, NULL, dnValidate, dnPretty}, + SLAP_SYNTAX_DN, NULL, dnValidate, dnPretty}, {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )", 0, NULL, rdnValidate, rdnPretty}, #ifdef LDAP_COMP_MATCH @@ -5241,7 +6202,7 @@ static slap_syntax_defs_rec syntax_defs[] = { {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )", 0, NULL, NULL, NULL}, {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )", - 0, NULL, nameUIDValidate, nameUIDPretty }, + SLAP_SYNTAX_DN, NULL, nameUIDValidate, nameUIDPretty }, {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )", 0, NULL, NULL, NULL}, {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )", @@ -5318,6 +6279,12 @@ static slap_syntax_defs_rec syntax_defs[] = { SLAP_SYNTAX_HIDE, NULL, NULL, NULL}, {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )", SLAP_SYNTAX_HIDE, NULL, NULL, NULL}, + {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )", + SLAP_SYNTAX_HIDE, NULL, + serialNumberAndIssuerSerialValidate, + serialNumberAndIssuerSerialPretty}, + {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )", + SLAP_SYNTAX_HIDE, NULL, NULL, NULL}, #ifdef SLAPD_AUTHPASSWD /* needs updating */ @@ -5357,12 +6324,20 @@ char *certificateListExactMatchSyntaxes[] = { "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */, NULL }; +char *attributeCertificateExactMatchSyntaxes[] = { + attributeCertificateSyntaxOID /* attributeCertificate */, + NULL +}; + #ifdef LDAP_COMP_MATCH char *componentFilterMatchSyntaxes[] = { "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */, + "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */, + attributeCertificateSyntaxOID /* attributeCertificate */, NULL }; #endif + char *directoryStringSyntaxes[] = { "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */, NULL @@ -5394,8 +6369,6 @@ char *objectIdentifierFirstComponentMatchSyntaxes[] = { * 2.5.13.33* keywordMatch * 2.5.13.36+ certificatePairExactMatch * 2.5.13.37+ certificatePairMatch - * 2.5.13.38+ certificateListExactMatch - * 2.5.13.39+ certificateListMatch * 2.5.13.40+ algorithmIdentifierMatch * 2.5.13.41* storedPrefixMatch * 2.5.13.42 attributeCertificateMatch @@ -5479,21 +6452,21 @@ static slap_mrule_defs_rec mrule_defs[] = { #ifdef LDAP_COMP_MATCH {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' " - "SYNTAX 1.2.36.79672281.1.5.2 )", + "SYNTAX 1.2.36.79672281.1.5.2 )", /* componentFilterMatch assertion */ SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes, NULL, NULL , componentFilterMatch, octetStringIndexer, octetStringFilter, NULL }, {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' " - "SYNTAX 1.2.36.79672281.1.5.3 )", + "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */ SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL, NULL, NULL , allComponentsMatch, octetStringIndexer, octetStringFilter, NULL }, {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' " - "SYNTAX 1.2.36.79672281.1.5.3 )", + "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */ SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL, NULL, NULL , directoryComponentsMatch, octetStringIndexer, octetStringFilter, @@ -5509,13 +6482,13 @@ static slap_mrule_defs_rec mrule_defs[] = { {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )", - SLAP_MR_ORDERING, directoryStringSyntaxes, + SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes, NULL, UTF8StringNormalize, octetStringOrderingMatch, NULL, NULL, "caseIgnoreMatch" }, {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */ SLAP_MR_SUBSTR, directoryStringSyntaxes, NULL, UTF8StringNormalize, directoryStringSubstringsMatch, octetStringSubstringsIndexer, octetStringSubstringsFilter, @@ -5530,13 +6503,13 @@ static slap_mrule_defs_rec mrule_defs[] = { {"( 2.5.13.6 NAME 'caseExactOrderingMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )", - SLAP_MR_ORDERING, directoryStringSyntaxes, + SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes, NULL, UTF8StringNormalize, octetStringOrderingMatch, NULL, NULL, "caseExactMatch" }, {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */ SLAP_MR_SUBSTR, directoryStringSyntaxes, NULL, UTF8StringNormalize, directoryStringSubstringsMatch, octetStringSubstringsIndexer, octetStringSubstringsFilter, @@ -5551,27 +6524,27 @@ static slap_mrule_defs_rec mrule_defs[] = { {"( 2.5.13.9 NAME 'numericStringOrderingMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )", - SLAP_MR_ORDERING, NULL, + SLAP_MR_ORDERING | SLAP_MR_EXT, NULL, NULL, numericStringNormalize, octetStringOrderingMatch, NULL, NULL, "numericStringMatch" }, {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */ SLAP_MR_SUBSTR, NULL, NULL, numericStringNormalize, octetStringSubstringsMatch, octetStringSubstringsIndexer, octetStringSubstringsFilter, "numericStringMatch" }, {"( 2.5.13.11 NAME 'caseIgnoreListMatch' " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", /* Postal Address */ SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, NULL, postalAddressNormalize, octetStringMatch, octetStringIndexer, octetStringFilter, NULL }, {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */ SLAP_MR_SUBSTR, NULL, NULL, NULL, NULL, NULL, NULL, "caseIgnoreListMatch" }, @@ -5592,7 +6565,7 @@ static slap_mrule_defs_rec mrule_defs[] = { {"( 2.5.13.15 NAME 'integerOrderingMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", - SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL, + SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL, NULL, NULL, integerMatch, NULL, NULL, "integerMatch" }, @@ -5613,7 +6586,7 @@ static slap_mrule_defs_rec mrule_defs[] = { {"( 2.5.13.18 NAME 'octetStringOrderingMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", - SLAP_MR_ORDERING, NULL, + SLAP_MR_ORDERING | SLAP_MR_EXT, NULL, NULL, NULL, octetStringOrderingMatch, NULL, NULL, "octetStringMatch" }, @@ -5634,7 +6607,7 @@ static slap_mrule_defs_rec mrule_defs[] = { NULL }, {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */ SLAP_MR_SUBSTR, NULL, NULL, telephoneNumberNormalize, octetStringSubstringsMatch, octetStringSubstringsIndexer, octetStringSubstringsFilter, @@ -5646,7 +6619,7 @@ static slap_mrule_defs_rec mrule_defs[] = { NULL, NULL, NULL, NULL, NULL, NULL }, {"( 2.5.13.23 NAME 'uniqueMemberMatch' " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", /* Name And Optional UID */ SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, NULL, uniqueMemberNormalize, uniqueMemberMatch, uniqueMemberIndexer, uniqueMemberFilter, @@ -5666,13 +6639,13 @@ static slap_mrule_defs_rec mrule_defs[] = { {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )", - SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL, + SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL, NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch, NULL, NULL, "generalizedTimeMatch" }, {"( 2.5.13.29 NAME 'integerFirstComponentMatch' " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */ SLAP_MR_EQUALITY | SLAP_MR_EXT, integerFirstComponentMatchSyntaxes, NULL, firstComponentNormalize, integerMatch, @@ -5680,7 +6653,7 @@ static slap_mrule_defs_rec mrule_defs[] = { NULL }, {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", /* OID */ SLAP_MR_EQUALITY | SLAP_MR_EXT, objectIdentifierFirstComponentMatchSyntaxes, NULL, firstComponentNormalize, octetStringMatch, @@ -5688,27 +6661,40 @@ static slap_mrule_defs_rec mrule_defs[] = { NULL }, {"( 2.5.13.34 NAME 'certificateExactMatch' " - "SYNTAX 1.3.6.1.1.15.1 )", + "SYNTAX 1.3.6.1.1.15.1 )", /* Certificate Exact Assertion */ SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes, NULL, certificateExactNormalize, octetStringMatch, octetStringIndexer, octetStringFilter, NULL }, {"( 2.5.13.35 NAME 'certificateMatch' " - "SYNTAX 1.3.6.1.1.15.2 )", + "SYNTAX 1.3.6.1.1.15.2 )", /* Certificate Assertion */ SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, {"( 2.5.13.38 NAME 'certificateListExactMatch' " - "SYNTAX 1.3.6.1.1.15.5 )", - SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, certificateListExactMatchSyntaxes, + "SYNTAX 1.3.6.1.1.15.5 )", /* Certificate List Exact Assertion */ + SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes, NULL, certificateListExactNormalize, octetStringMatch, octetStringIndexer, octetStringFilter, NULL }, {"( 2.5.13.39 NAME 'certificateListMatch' " - "SYNTAX 1.3.6.1.1.15.6 )", + "SYNTAX 1.3.6.1.1.15.6 )", /* Certificate List Assertion */ + SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL }, + + {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' " + "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )", + SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes, + NULL, attributeCertificateExactNormalize, octetStringMatch, + octetStringIndexer, octetStringFilter, + NULL }, + + {"( 2.5.13.46 NAME 'attributeCertificateMatch' " + "SYNTAX " attributeCertificateAssertionSyntaxOID " )", SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, @@ -5744,7 +6730,7 @@ static slap_mrule_defs_rec mrule_defs[] = { #ifdef SLAPD_AUTHPASSWD /* needs updating */ {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", /* Octet String */ SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL, NULL, NULL, authPasswordMatch, NULL, NULL, @@ -5752,14 +6738,14 @@ static slap_mrule_defs_rec mrule_defs[] = { #endif {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */ SLAP_MR_EXT, NULL, NULL, NULL, integerBitAndMatch, NULL, NULL, "integerMatch" }, {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */ SLAP_MR_EXT, NULL, NULL, NULL, integerBitOrMatch, NULL, NULL, @@ -5788,8 +6774,8 @@ static slap_mrule_defs_rec mrule_defs[] = { {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' " "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )", - SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL, - NULL, NULL, csnOrderingMatch, + SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL, + NULL, csnNormalize, csnOrderingMatch, NULL, NULL, "CSNMatch" }, @@ -5802,7 +6788,7 @@ static slap_mrule_defs_rec mrule_defs[] = { /* FIXME: OID is unused, but not registered yet */ {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' " - "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )", + "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )", /* OpenLDAP authz */ SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL, NULL, authzNormalize, authzMatch, NULL, NULL, @@ -5868,6 +6854,7 @@ schema_destroy( void ) syn_destroy(); if( schema_init_done ) { + ldap_pvt_thread_mutex_destroy( &ad_index_mutex ); ldap_pvt_thread_mutex_destroy( &ad_undef_mutex ); ldap_pvt_thread_mutex_destroy( &oc_undef_mutex ); }