Commit ad19032b authored by Sang Seok Lim's avatar Sang Seok Lim
Browse files

This patch provides support for rdnMatch matching rule and RDN syntax in

RFC 3687. For now, both the attribute and assertion values are considered
as RDNs. Refer to ITS#3207 to find related discussion.
parent 8f6cce32
......@@ -54,6 +54,53 @@
#define AVA_PRIVATE( ava ) ( ( AttributeDescription * )(ava)->la_private )
static int
LDAPRDN_validate( LDAPRDN rdn )
{
int iAVA;
int rc;
assert( rdn );
for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
LDAPAVA *ava = rdn[ iAVA ];
AttributeDescription *ad;
slap_syntax_validate_func *validate = NULL;
assert( ava );
if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
const char *text = NULL;
rc = slap_bv2ad( &ava->la_attr, &ad, &text );
if ( rc != LDAP_SUCCESS ) {
return LDAP_INVALID_SYNTAX;
}
ava->la_private = ( void * )ad;
}
/*
* Replace attr oid/name with the canonical name
*/
ava->la_attr = ad->ad_cname;
validate = ad->ad_type->sat_syntax->ssyn_validate;
if ( validate ) {
/*
* validate value by validate function
*/
rc = ( *validate )( ad->ad_type->sat_syntax,
&ava->la_value );
if ( rc != LDAP_SUCCESS ) {
return LDAP_INVALID_SYNTAX;
}
}
}
}
/*
* In-place, schema-aware validation of the
* structural representation of a distinguished name.
......@@ -154,6 +201,46 @@ dnValidate(
return LDAP_SUCCESS;
}
int
rdnValidate(
Syntax *syntax,
struct berval *in )
{
int rc;
LDAPDN dn = NULL;
LDAPRDN rdn;
char* p;
assert( in );
if ( in->bv_len == 0 ) {
return LDAP_SUCCESS;
} else if ( in->bv_len > SLAP_LDAPDN_MAXLEN ) {
return LDAP_INVALID_SYNTAX;
}
rc = ldap_bv2rdn_x( in , &rdn, (char **) &p,
LDAP_DN_FORMAT_LDAP, NULL);
if ( rc != LDAP_SUCCESS ) {
return LDAP_INVALID_SYNTAX;
}
assert( strlen( in->bv_val ) == in->bv_len );
/*
* Schema-aware validate
*/
rc = LDAPRDN_validate( rdn );
ldap_rdnfree( rdn );
if ( rc != LDAP_SUCCESS ) {
return LDAP_INVALID_SYNTAX;
}
return LDAP_SUCCESS;
}
/*
* AVA sorting inside a RDN
*
......@@ -234,6 +321,119 @@ AVA_Sort( LDAPRDN rdn, int iAVA )
}
}
static int
LDAPRDN_rewrite( LDAPRDN rdn, unsigned flags, void *ctx )
{
int rc;
int iAVA;
for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
LDAPAVA *ava = rdn[ iAVA ];
AttributeDescription *ad;
slap_syntax_validate_func *validf = NULL;
slap_mr_normalize_func *normf = NULL;
slap_syntax_transform_func *transf = NULL;
MatchingRule *mr = NULL;
struct berval bv = BER_BVNULL;
int do_sort = 0;
assert( ava );
if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
const char *text = NULL;
rc = slap_bv2ad( &ava->la_attr, &ad, &text );
if ( rc != LDAP_SUCCESS ) {
return LDAP_INVALID_SYNTAX;
}
ava->la_private = ( void * )ad;
do_sort = 1;
}
/*
* Replace attr oid/name with the canonical name
*/
ava->la_attr = ad->ad_cname;
if( ava->la_flags & LDAP_AVA_BINARY ) {
if( ava->la_value.bv_len == 0 ) {
/* BER encoding is empty */
return LDAP_INVALID_SYNTAX;
}
/* AVA is binary encoded, don't muck with it */
} else if( flags & SLAP_LDAPDN_PRETTY ) {
transf = ad->ad_type->sat_syntax->ssyn_pretty;
if( !transf ) {
validf = ad->ad_type->sat_syntax->ssyn_validate;
}
} else { /* normalization */
validf = ad->ad_type->sat_syntax->ssyn_validate;
mr = ad->ad_type->sat_equality;
if( mr ) normf = mr->smr_normalize;
}
if ( validf ) {
/* validate value before normalization */
rc = ( *validf )( ad->ad_type->sat_syntax,
ava->la_value.bv_len
? &ava->la_value
: (struct berval *) &slap_empty_bv );
if ( rc != LDAP_SUCCESS ) {
return LDAP_INVALID_SYNTAX;
}
}
if ( transf ) {
/*
* transform value by pretty function
* if value is empty, use empty_bv
*/
rc = ( *transf )( ad->ad_type->sat_syntax,
ava->la_value.bv_len
? &ava->la_value
: (struct berval *) &slap_empty_bv,
&bv, ctx );
if ( rc != LDAP_SUCCESS ) {
return LDAP_INVALID_SYNTAX;
}
}
if ( normf ) {
/*
* normalize value
* if value is empty, use empty_bv
*/
rc = ( *normf )(
SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
ad->ad_type->sat_syntax,
mr,
ava->la_value.bv_len
? &ava->la_value
: (struct berval *) &slap_empty_bv,
&bv, ctx );
if ( rc != LDAP_SUCCESS ) {
return LDAP_INVALID_SYNTAX;
}
}
if( bv.bv_val ) {
if ( ava->la_flags & LDAP_AVA_FREE_VALUE )
ber_memfree_x( ava->la_value.bv_val, ctx );
ava->la_value = bv;
ava->la_flags |= LDAP_AVA_FREE_VALUE;
}
if( do_sort ) AVA_Sort( rdn, iAVA );
}
return LDAP_SUCCESS;
}
/*
* In-place, schema-aware normalization / "pretty"ing of the
* structural representation of a distinguished name.
......@@ -417,6 +617,64 @@ dnNormalize(
return LDAP_SUCCESS;
}
int
rdnNormalize(
slap_mask_t use,
Syntax *syntax,
MatchingRule *mr,
struct berval *val,
struct berval *out,
void *ctx)
{
assert( val );
assert( out );
Debug( LDAP_DEBUG_TRACE, ">>> dnNormalize: <%s>\n", val->bv_val, 0, 0 );
if ( val->bv_len != 0 ) {
LDAPRDN rdn = NULL;
int rc;
char* p;
/*
* Go to structural representation
*/
rc = ldap_bv2rdn_x( val , &rdn, (char **) &p,
LDAP_DN_FORMAT_LDAP, ctx);
if ( rc != LDAP_SUCCESS ) {
return LDAP_INVALID_SYNTAX;
}
assert( strlen( val->bv_val ) == val->bv_len );
/*
* Schema-aware rewrite
*/
if ( LDAPRDN_rewrite( rdn, 0, ctx ) != LDAP_SUCCESS ) {
ldap_rdnfree_x( rdn, ctx );
return LDAP_INVALID_SYNTAX;
}
/*
* Back to string representation
*/
rc = ldap_rdn2bv_x( rdn, out,
LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
ldap_rdnfree_x( rdn, ctx );
if ( rc != LDAP_SUCCESS ) {
return LDAP_INVALID_SYNTAX;
}
} else {
ber_dupbv_x( out, val, ctx );
}
Debug( LDAP_DEBUG_TRACE, "<<< dnNormalize: <%s>\n", out->bv_val, 0, 0 );
return LDAP_SUCCESS;
}
int
dnPretty(
Syntax *syntax,
......@@ -482,6 +740,74 @@ dnPretty(
return LDAP_SUCCESS;
}
int
rdnPretty(
Syntax *syntax,
struct berval *val,
struct berval *out,
void *ctx)
{
assert( val );
assert( out );
#ifdef NEW_LOGGING
LDAP_LOG( OPERATION, ARGS, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 );
#else
Debug( LDAP_DEBUG_TRACE, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 );
#endif
if ( val->bv_len == 0 ) {
ber_dupbv_x( out, val, ctx );
} else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
return LDAP_INVALID_SYNTAX;
} else {
LDAPRDN rdn = NULL;
int rc;
char* p;
/* FIXME: should be liberal in what we accept */
rc = ldap_bv2rdn_x( val , &rdn, (char **) &p,
LDAP_DN_FORMAT_LDAP, ctx);
if ( rc != LDAP_SUCCESS ) {
return LDAP_INVALID_SYNTAX;
}
assert( strlen( val->bv_val ) == val->bv_len );
/*
* Schema-aware rewrite
*/
if ( LDAPRDN_rewrite( rdn, SLAP_LDAPDN_PRETTY, ctx ) != LDAP_SUCCESS ) {
ldap_rdnfree_x( rdn, ctx );
return LDAP_INVALID_SYNTAX;
}
/* FIXME: not sure why the default isn't pretty */
/* RE: the default is the form that is used as
* an internal representation; the pretty form
* is a variant */
rc = ldap_rdn2bv_x( rdn, out,
LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY, ctx );
ldap_rdnfree_x( rdn, ctx );
if ( rc != LDAP_SUCCESS ) {
return LDAP_INVALID_SYNTAX;
}
}
#ifdef NEW_LOGGING
LDAP_LOG( OPERATION, ARGS, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
#else
Debug( LDAP_DEBUG_TRACE, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
#endif
return LDAP_SUCCESS;
}
int
dnPrettyNormalDN(
Syntax *syntax,
......@@ -668,9 +994,44 @@ dnMatch(
return( LDAP_SUCCESS );
}
int
rdnMatch(
int *matchp,
slap_mask_t flags,
Syntax *syntax,
MatchingRule *mr,
struct berval *value,
void *assertedValue )
{
int match;
struct berval *asserted = (struct berval *) assertedValue;
assert( matchp );
assert( value );
assert( assertedValue );
match = value->bv_len - asserted->bv_len;
if ( match == 0 ) {
match = memcmp( value->bv_val, asserted->bv_val,
value->bv_len );
}
#ifdef NEW_LOGGING
LDAP_LOG( CONFIG, ENTRY, "dnMatch: %d\n %s\n %s\n",
match, value->bv_val, asserted->bv_val );
#else
Debug( LDAP_DEBUG_ARGS, "dnMatch %d\n\t\"%s\"\n\t\"%s\"\n",
match, value->bv_val, asserted->bv_val );
#endif
*matchp = match;
return( LDAP_SUCCESS );
}
/*
* dnParent - dn's parent, in-place
*
* note: the incoming dn is assumed to be normalized/prettyfied,
* so that escaped rdn/ava separators are in '\'+hexpair form
*/
......@@ -768,7 +1129,7 @@ dn_rdnlen(
* LDAP_INVALID_SYNTAX otherwise (including a sequence of rdns)
*/
int
rdnValidate( struct berval *rdn )
rdn_validate( struct berval *rdn )
{
#if 1
/* Major cheat!
......@@ -780,7 +1141,6 @@ rdnValidate( struct berval *rdn )
{
return LDAP_INVALID_SYNTAX;
}
return strchr( rdn->bv_val, ',' ) == NULL
? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
......
......@@ -236,7 +236,7 @@ do_modrdn(
goto cleanup;
}
if( rdnValidate( &op->orr_newrdn ) != LDAP_SUCCESS ) {
if( rdn_validate( &op->orr_newrdn ) != LDAP_SUCCESS ) {
#ifdef NEW_LOGGING
LDAP_LOG( OPERATION, ERR,
"do_modrdn: invalid rdn (%s).\n", op->orr_newrdn.bv_val, 0, 0 );
......
......@@ -443,11 +443,18 @@ LDAP_SLAPD_V (int) slapd_register_slp;
LDAP_SLAPD_F (int) dnValidate LDAP_P((
Syntax *syntax,
struct berval *val ));
LDAP_SLAPD_F (int) rdnValidate LDAP_P((
Syntax *syntax,
struct berval *val ));
LDAP_SLAPD_F (slap_mr_normalize_func) dnNormalize;
LDAP_SLAPD_F (slap_mr_normalize_func) rdnNormalize;
LDAP_SLAPD_F (slap_syntax_transform_func) dnPretty;
LDAP_SLAPD_F (slap_syntax_transform_func) rdnPretty;
LDAP_SLAPD_F (int) dnPrettyNormal LDAP_P((
Syntax *syntax,
struct berval *val,
......@@ -463,13 +470,21 @@ LDAP_SLAPD_F (int) dnMatch LDAP_P((
struct berval *value,
void *assertedValue ));
LDAP_SLAPD_F (int) rdnMatch LDAP_P((
int *matchp,
slap_mask_t flags,
Syntax *syntax,
MatchingRule *mr,
struct berval *value,
void *assertedValue ));
LDAP_SLAPD_F (int) dnIsSuffix LDAP_P((
const struct berval *dn, const struct berval *suffix ));
LDAP_SLAPD_F (int) dnExtractRdn LDAP_P((
struct berval *dn, struct berval *rdn, void *ctx ));
LDAP_SLAPD_F (int) rdnValidate LDAP_P(( struct berval * rdn ));
LDAP_SLAPD_F (int) rdn_validate LDAP_P(( struct berval * rdn ));
LDAP_SLAPD_F (int) dn_rdnlen LDAP_P(( Backend *be, struct berval *dn ));
......
......@@ -3034,6 +3034,10 @@ static slap_syntax_defs_rec syntax_defs[] = {
0, countryStringValidate, NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
0, dnValidate, dnPretty},
{"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
0, rdnValidate, rdnPretty},
{"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
0, NULL, NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
......@@ -3239,6 +3243,12 @@ static slap_mrule_defs_rec mrule_defs[] = {
NULL, dnNormalize, dnMatch,
octetStringIndexer, octetStringFilter,
NULL },
{"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
"SYNTAX 1.2.36.79672281.1.5.0 )",
SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
NULL, rdnNormalize, rdnMatch,
octetStringIndexer, octetStringFilter,
NULL },
{"( 2.5.13.2 NAME 'caseIgnoreMatch' "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment