1998-08-09 08:43:13 +08:00
|
|
|
/* dn.c - routines for dealing with distinguished names */
|
1999-09-09 03:06:24 +08:00
|
|
|
/* $OpenLDAP$ */
|
1999-08-07 07:07:46 +08:00
|
|
|
/*
|
2002-01-05 05:17:25 +08:00
|
|
|
* Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
|
1999-08-07 07:07:46 +08:00
|
|
|
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
|
|
|
|
*/
|
1998-08-09 08:43:13 +08:00
|
|
|
|
|
|
|
#include "portable.h"
|
1998-10-25 09:41:42 +08:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include <ac/ctype.h>
|
|
|
|
#include <ac/socket.h>
|
|
|
|
#include <ac/string.h>
|
|
|
|
#include <ac/time.h>
|
|
|
|
|
1999-08-25 14:44:08 +08:00
|
|
|
#include "ldap_pvt.h"
|
|
|
|
|
1998-08-09 08:43:13 +08:00
|
|
|
#include "slap.h"
|
|
|
|
|
2001-12-23 09:19:46 +08:00
|
|
|
#define SLAP_LDAPDN_PRETTY 0x1
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The DN syntax-related functions take advantage of the dn representation
|
|
|
|
* handling functions ldap_str2dn/ldap_dn2str. The latter are not schema-
|
|
|
|
* aware, so the attributes and their values need be validated (and possibly
|
|
|
|
* normalized). In the current implementation the required validation/nor-
|
|
|
|
* malization/"pretty"ing are done on newly created DN structural represen-
|
|
|
|
* tations; however the idea is to move towards DN handling in structural
|
|
|
|
* representation instead of the current string representation. To this
|
|
|
|
* purpose, we need to do only the required operations and keep track of
|
|
|
|
* what has been done to minimize their impact on performances.
|
|
|
|
*
|
|
|
|
* Developers are strongly encouraged to use this feature, to speed-up
|
|
|
|
* its stabilization.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define AVA_PRIVATE( ava ) ( ( AttributeDescription * )(ava)->la_private )
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In-place, schema-aware validation of the
|
|
|
|
* structural representation of a distinguished name.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
LDAPDN_validate( LDAPDN *dn )
|
|
|
|
{
|
|
|
|
int iRDN;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
assert( dn );
|
|
|
|
|
2001-12-30 14:56:57 +08:00
|
|
|
for ( iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
|
|
|
|
LDAPRDN *rdn = dn[ 0 ][ iRDN ];
|
2001-12-23 09:19:46 +08:00
|
|
|
int iAVA;
|
|
|
|
|
|
|
|
assert( rdn );
|
|
|
|
|
2001-12-30 14:56:57 +08:00
|
|
|
for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
|
|
|
|
LDAPAVA *ava = rdn[ 0 ][ iAVA ];
|
2001-12-23 09:19:46 +08:00
|
|
|
AttributeDescription *ad;
|
|
|
|
slap_syntax_validate_func *validate = NULL;
|
|
|
|
|
|
|
|
assert( ava );
|
|
|
|
|
|
|
|
if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
|
|
|
|
const char *text = NULL;
|
|
|
|
|
2001-12-29 18:35:24 +08:00
|
|
|
rc = slap_bv2ad( &ava->la_attr, &ad, &text );
|
2001-12-23 09:19:46 +08:00
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
ava->la_private = ( void * )ad;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Replace attr oid/name with the canonical name
|
|
|
|
*/
|
2002-01-01 17:40:57 +08:00
|
|
|
ava->la_attr = ad->ad_cname;
|
2001-12-23 09:19:46 +08:00
|
|
|
|
|
|
|
validate = ad->ad_type->sat_syntax->ssyn_validate;
|
|
|
|
|
|
|
|
if ( validate ) {
|
|
|
|
/*
|
|
|
|
* validate value by validate function
|
|
|
|
*/
|
|
|
|
rc = ( *validate )( ad->ad_type->sat_syntax,
|
2001-12-29 18:35:24 +08:00
|
|
|
&ava->la_value );
|
2001-12-23 09:19:46 +08:00
|
|
|
|
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return LDAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2001-12-08 14:57:06 +08:00
|
|
|
/*
|
2001-12-23 09:19:46 +08:00
|
|
|
* dn validate routine
|
2001-12-08 14:57:06 +08:00
|
|
|
*/
|
2001-12-23 09:19:46 +08:00
|
|
|
int
|
|
|
|
dnValidate(
|
|
|
|
Syntax *syntax,
|
|
|
|
struct berval *in )
|
2001-12-08 14:57:06 +08:00
|
|
|
{
|
2001-12-23 09:19:46 +08:00
|
|
|
int rc;
|
|
|
|
LDAPDN *dn = NULL;
|
|
|
|
|
|
|
|
assert( in );
|
|
|
|
|
|
|
|
if ( in->bv_len == 0 ) {
|
|
|
|
return( LDAP_SUCCESS );
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = ldap_str2dn( in->bv_val, &dn, LDAP_DN_FORMAT_LDAP );
|
|
|
|
|
2001-12-08 14:57:06 +08:00
|
|
|
/*
|
2001-12-23 09:19:46 +08:00
|
|
|
* Schema-aware validate
|
2001-12-08 14:57:06 +08:00
|
|
|
*/
|
2001-12-23 09:19:46 +08:00
|
|
|
if ( rc == LDAP_SUCCESS ) {
|
|
|
|
rc = LDAPDN_validate( dn );
|
2001-12-28 18:04:53 +08:00
|
|
|
ldap_dnfree( dn );
|
2001-12-23 09:19:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
|
|
return( LDAP_INVALID_SYNTAX );
|
|
|
|
}
|
|
|
|
|
|
|
|
return( LDAP_SUCCESS );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* AVA sorting inside a RDN
|
|
|
|
*
|
|
|
|
* rule: sort attributeTypes in alphabetical order; in case of multiple
|
|
|
|
* occurrences of the same attributeType, sort values in byte order
|
|
|
|
* (use memcmp, which implies alphabetical order in case of IA5 value;
|
|
|
|
* this should guarantee the repeatability of the operation).
|
|
|
|
*
|
2002-01-17 02:51:20 +08:00
|
|
|
* Note: the sorting can be slightly improved by sorting first
|
|
|
|
* by attribute type length, then by alphabetical order.
|
|
|
|
*
|
2001-12-23 09:19:46 +08:00
|
|
|
* uses a linear search; should be fine since the number of AVAs in
|
|
|
|
* a RDN should be limited.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
AVA_Sort( LDAPRDN *rdn, int iAVA )
|
|
|
|
{
|
|
|
|
int i;
|
2001-12-30 14:56:57 +08:00
|
|
|
LDAPAVA *ava_in = rdn[ 0 ][ iAVA ];
|
2001-12-23 09:19:46 +08:00
|
|
|
|
|
|
|
assert( rdn );
|
|
|
|
assert( ava_in );
|
|
|
|
|
|
|
|
for ( i = 0; i < iAVA; i++ ) {
|
2001-12-30 14:56:57 +08:00
|
|
|
LDAPAVA *ava = rdn[ 0 ][ i ];
|
2001-12-23 09:19:46 +08:00
|
|
|
int a, j;
|
|
|
|
|
|
|
|
assert( ava );
|
|
|
|
|
2001-12-29 18:35:24 +08:00
|
|
|
a = strcmp( ava_in->la_attr.bv_val, ava->la_attr.bv_val );
|
2001-12-23 09:19:46 +08:00
|
|
|
|
|
|
|
if ( a > 0 ) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( a == 0 ) {
|
|
|
|
int v, d;
|
|
|
|
|
2001-12-29 18:35:24 +08:00
|
|
|
d = ava_in->la_value.bv_len - ava->la_value.bv_len;
|
2001-12-23 09:19:46 +08:00
|
|
|
|
2001-12-29 18:35:24 +08:00
|
|
|
v = memcmp( ava_in->la_value.bv_val,
|
|
|
|
ava->la_value.bv_val,
|
|
|
|
d <= 0 ? ava_in->la_value.bv_len
|
|
|
|
: ava->la_value.bv_len );
|
2001-12-23 09:19:46 +08:00
|
|
|
|
|
|
|
if ( v == 0 && d != 0 ) {
|
|
|
|
v = d;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( v <= 0 ) {
|
|
|
|
/*
|
|
|
|
* got it!
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ++i == iAVA ) {
|
|
|
|
/*
|
|
|
|
* already sorted
|
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-12-30 14:56:57 +08:00
|
|
|
ava = rdn[ 0 ][ i ];
|
2002-01-16 20:06:42 +08:00
|
|
|
a = strcmp( ava_in->la_attr.bv_val,
|
|
|
|
ava->la_attr.bv_val );
|
2001-12-23 09:19:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* move ahead
|
|
|
|
*/
|
|
|
|
for ( j = iAVA; j > i; j-- ) {
|
2001-12-30 14:56:57 +08:00
|
|
|
rdn[ 0 ][ j ] = rdn[ 0 ][ j - 1 ];
|
2001-12-23 09:19:46 +08:00
|
|
|
}
|
2001-12-30 14:56:57 +08:00
|
|
|
rdn[ 0 ][ i ] = ava_in;
|
2001-12-23 09:19:46 +08:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In-place, schema-aware normalization / "pretty"ing of the
|
|
|
|
* structural representation of a distinguished name.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
LDAPDN_rewrite( LDAPDN *dn, unsigned flags )
|
|
|
|
{
|
|
|
|
int iRDN;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
assert( dn );
|
|
|
|
|
2001-12-30 14:56:57 +08:00
|
|
|
for ( iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
|
|
|
|
LDAPRDN *rdn = dn[ 0 ][ iRDN ];
|
2001-12-23 09:19:46 +08:00
|
|
|
int iAVA;
|
|
|
|
|
|
|
|
assert( rdn );
|
|
|
|
|
2001-12-30 14:56:57 +08:00
|
|
|
for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
|
|
|
|
LDAPAVA *ava = rdn[ 0 ][ iAVA ];
|
2001-12-23 09:19:46 +08:00
|
|
|
AttributeDescription *ad;
|
|
|
|
slap_syntax_transform_func *transf = NULL;
|
|
|
|
MatchingRule *mr;
|
2001-12-30 08:24:44 +08:00
|
|
|
struct berval bv = { 0, NULL };
|
2002-01-01 21:32:10 +08:00
|
|
|
int do_sort = 0;
|
2001-12-08 14:57:06 +08:00
|
|
|
|
2001-12-23 09:19:46 +08:00
|
|
|
assert( ava );
|
|
|
|
|
|
|
|
if ( ( ad = AVA_PRIVATE( ava ) ) == NULL ) {
|
|
|
|
const char *text = NULL;
|
|
|
|
|
2001-12-29 18:35:24 +08:00
|
|
|
rc = slap_bv2ad( &ava->la_attr, &ad, &text );
|
2001-12-23 09:19:46 +08:00
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
ava->la_private = ( void * )ad;
|
2002-01-01 21:32:10 +08:00
|
|
|
do_sort = 1;
|
2001-12-23 09:19:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Replace attr oid/name with the canonical name
|
|
|
|
*/
|
2001-12-30 17:42:58 +08:00
|
|
|
ava->la_attr = ad->ad_cname;
|
2001-12-23 09:19:46 +08:00
|
|
|
|
|
|
|
if( flags & SLAP_LDAPDN_PRETTY ) {
|
|
|
|
transf = ad->ad_type->sat_syntax->ssyn_pretty;
|
|
|
|
mr = NULL;
|
|
|
|
} else {
|
|
|
|
transf = ad->ad_type->sat_syntax->ssyn_normalize;
|
|
|
|
mr = ad->ad_type->sat_equality;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( transf ) {
|
|
|
|
/*
|
|
|
|
* transform value by normalize/pretty function
|
|
|
|
*/
|
|
|
|
rc = ( *transf )( ad->ad_type->sat_syntax,
|
2001-12-29 18:35:24 +08:00
|
|
|
&ava->la_value, &bv );
|
2001-12-23 09:19:46 +08:00
|
|
|
|
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( mr && ( mr->smr_usage & SLAP_MR_DN_FOLD ) ) {
|
2001-12-29 23:01:10 +08:00
|
|
|
char *s = bv.bv_val;
|
2001-12-23 09:19:46 +08:00
|
|
|
|
2001-12-29 23:01:10 +08:00
|
|
|
ber_str2bv( UTF8normalize( bv.bv_val ? &bv
|
2002-01-03 01:06:56 +08:00
|
|
|
: &ava->la_value, LDAP_UTF8_CASEFOLD ),
|
2001-12-29 23:01:10 +08:00
|
|
|
0, 0, &bv );
|
|
|
|
free( s );
|
2001-12-23 09:19:46 +08:00
|
|
|
}
|
|
|
|
|
2001-12-29 23:01:10 +08:00
|
|
|
if( bv.bv_val ) {
|
2001-12-29 18:35:24 +08:00
|
|
|
free( ava->la_value.bv_val );
|
2001-12-29 23:01:10 +08:00
|
|
|
ava->la_value = bv;
|
2001-12-23 09:19:46 +08:00
|
|
|
}
|
|
|
|
|
2002-01-01 21:32:10 +08:00
|
|
|
if( do_sort ) AVA_Sort( rdn, iAVA );
|
2001-12-23 09:19:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return LDAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dn normalize routine
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
dnNormalize(
|
|
|
|
Syntax *syntax,
|
|
|
|
struct berval *val,
|
|
|
|
struct berval **normalized )
|
|
|
|
{
|
2001-12-29 12:48:00 +08:00
|
|
|
struct berval *out;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
assert( normalized && *normalized == NULL );
|
|
|
|
|
|
|
|
out = ch_malloc( sizeof( struct berval ) );
|
|
|
|
rc = dnNormalize2( syntax, val, out );
|
|
|
|
if ( rc != LDAP_SUCCESS )
|
|
|
|
free( out );
|
|
|
|
else
|
|
|
|
*normalized = out;
|
|
|
|
return rc;
|
|
|
|
}
|
2001-12-23 09:19:46 +08:00
|
|
|
|
2001-12-29 12:48:00 +08:00
|
|
|
int
|
|
|
|
dnNormalize2(
|
|
|
|
Syntax *syntax,
|
|
|
|
struct berval *val,
|
|
|
|
struct berval *out )
|
|
|
|
{
|
2001-12-23 09:19:46 +08:00
|
|
|
assert( val );
|
2001-12-29 12:48:00 +08:00
|
|
|
assert( out );
|
2001-12-23 09:19:46 +08:00
|
|
|
|
2001-12-29 12:48:00 +08:00
|
|
|
Debug( LDAP_DEBUG_TRACE, ">>> dnNormalize: <%s>\n", val->bv_val, 0, 0 );
|
2001-12-25 02:38:20 +08:00
|
|
|
|
2001-12-23 09:19:46 +08:00
|
|
|
if ( val->bv_len != 0 ) {
|
|
|
|
LDAPDN *dn = NULL;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Go to structural representation
|
|
|
|
*/
|
|
|
|
rc = ldap_str2dn( val->bv_val, &dn, LDAP_DN_FORMAT_LDAP );
|
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Schema-aware rewrite
|
|
|
|
*/
|
|
|
|
if ( LDAPDN_rewrite( dn, 0 ) != LDAP_SUCCESS ) {
|
2001-12-24 06:46:37 +08:00
|
|
|
ldap_dnfree( dn );
|
2001-12-23 09:19:46 +08:00
|
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Back to string representation
|
|
|
|
*/
|
2001-12-28 18:04:53 +08:00
|
|
|
rc = ldap_dn2bv( dn, out, LDAP_DN_FORMAT_LDAPV3 );
|
2001-12-23 09:19:46 +08:00
|
|
|
|
2001-12-24 06:46:37 +08:00
|
|
|
ldap_dnfree( dn );
|
2001-12-23 09:19:46 +08:00
|
|
|
|
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
}
|
|
|
|
} else {
|
2001-12-29 12:48:00 +08:00
|
|
|
ber_dupbv( out, val );
|
2001-12-23 09:19:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Debug( LDAP_DEBUG_TRACE, "<<< dnNormalize: <%s>\n", out->bv_val, 0, 0 );
|
|
|
|
|
|
|
|
return LDAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dn "pretty"ing routine
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
dnPretty(
|
|
|
|
Syntax *syntax,
|
|
|
|
struct berval *val,
|
|
|
|
struct berval **pretty)
|
|
|
|
{
|
2001-12-29 12:48:00 +08:00
|
|
|
struct berval *out;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
assert( pretty && *pretty == NULL );
|
|
|
|
|
|
|
|
out = ch_malloc( sizeof( struct berval ) );
|
|
|
|
rc = dnPretty2( syntax, val, out );
|
|
|
|
if ( rc != LDAP_SUCCESS )
|
|
|
|
free( out );
|
|
|
|
else
|
|
|
|
*pretty = out;
|
|
|
|
return rc;
|
|
|
|
}
|
2001-12-23 09:19:46 +08:00
|
|
|
|
2001-12-29 12:48:00 +08:00
|
|
|
int
|
|
|
|
dnPretty2(
|
|
|
|
Syntax *syntax,
|
|
|
|
struct berval *val,
|
|
|
|
struct berval *out)
|
|
|
|
{
|
2001-12-23 09:19:46 +08:00
|
|
|
assert( val );
|
2001-12-29 12:48:00 +08:00
|
|
|
assert( out );
|
|
|
|
|
|
|
|
Debug( LDAP_DEBUG_TRACE, ">>> dnPretty: <%s>\n", val->bv_val, 0, 0 );
|
2001-12-23 09:19:46 +08:00
|
|
|
|
|
|
|
if ( val->bv_len != 0 ) {
|
|
|
|
LDAPDN *dn = NULL;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* FIXME: should be liberal in what we accept */
|
|
|
|
rc = ldap_str2dn( val->bv_val, &dn, LDAP_DN_FORMAT_LDAP );
|
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Schema-aware rewrite
|
|
|
|
*/
|
|
|
|
if ( LDAPDN_rewrite( dn, SLAP_LDAPDN_PRETTY ) != LDAP_SUCCESS ) {
|
2001-12-24 06:46:37 +08:00
|
|
|
ldap_dnfree( dn );
|
2001-12-23 09:19:46 +08:00
|
|
|
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 */
|
2001-12-28 18:04:53 +08:00
|
|
|
rc = ldap_dn2bv( dn, out,
|
2001-12-23 09:19:46 +08:00
|
|
|
LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY );
|
|
|
|
|
2001-12-24 06:46:37 +08:00
|
|
|
ldap_dnfree( dn );
|
2001-12-23 09:19:46 +08:00
|
|
|
|
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
}
|
|
|
|
} else {
|
2001-12-29 12:48:00 +08:00
|
|
|
ber_dupbv( out, val );
|
2001-12-23 09:19:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Debug( LDAP_DEBUG_TRACE, "<<< dnPretty: <%s>\n", out->bv_val, 0, 0 );
|
|
|
|
|
|
|
|
return LDAP_SUCCESS;
|
2001-12-08 14:57:06 +08:00
|
|
|
}
|
2001-12-23 09:19:46 +08:00
|
|
|
|
2001-12-28 15:27:15 +08:00
|
|
|
/*
|
|
|
|
* Combination of both dnPretty and dnNormalize
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
dnPrettyNormal(
|
|
|
|
Syntax *syntax,
|
|
|
|
struct berval *val,
|
|
|
|
struct berval *pretty,
|
|
|
|
struct berval *normal)
|
|
|
|
{
|
|
|
|
Debug( LDAP_DEBUG_TRACE, ">>> dnPrettyNormal: <%s>\n", val->bv_val, 0, 0 );
|
|
|
|
|
|
|
|
assert( val );
|
|
|
|
assert( pretty );
|
|
|
|
assert( normal );
|
|
|
|
|
|
|
|
if ( val->bv_len != 0 ) {
|
|
|
|
LDAPDN *dn = NULL;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
pretty->bv_val = NULL;
|
|
|
|
normal->bv_val = NULL;
|
|
|
|
pretty->bv_len = 0;
|
|
|
|
normal->bv_len = 0;
|
|
|
|
|
|
|
|
/* FIXME: should be liberal in what we accept */
|
|
|
|
rc = ldap_str2dn( val->bv_val, &dn, LDAP_DN_FORMAT_LDAP );
|
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Schema-aware rewrite
|
|
|
|
*/
|
|
|
|
if ( LDAPDN_rewrite( dn, SLAP_LDAPDN_PRETTY ) != LDAP_SUCCESS ) {
|
|
|
|
ldap_dnfree( dn );
|
|
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
}
|
|
|
|
|
2001-12-28 18:04:53 +08:00
|
|
|
rc = ldap_dn2bv( dn, pretty,
|
2001-12-28 15:27:15 +08:00
|
|
|
LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY );
|
|
|
|
|
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
|
|
ldap_dnfree( dn );
|
|
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( LDAPDN_rewrite( dn, 0 ) != LDAP_SUCCESS ) {
|
|
|
|
ldap_dnfree( dn );
|
|
|
|
free( pretty->bv_val );
|
|
|
|
pretty->bv_val = NULL;
|
|
|
|
pretty->bv_len = 0;
|
|
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
}
|
|
|
|
|
2001-12-28 18:04:53 +08:00
|
|
|
rc = ldap_dn2bv( dn, normal, LDAP_DN_FORMAT_LDAPV3 );
|
2001-12-28 15:27:15 +08:00
|
|
|
|
|
|
|
ldap_dnfree( dn );
|
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
|
|
free( pretty->bv_val );
|
|
|
|
pretty->bv_val = NULL;
|
|
|
|
pretty->bv_len = 0;
|
|
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ber_dupbv( pretty, val );
|
|
|
|
ber_dupbv( normal, val );
|
|
|
|
}
|
|
|
|
|
|
|
|
Debug( LDAP_DEBUG_TRACE, "<<< dnPrettyNormal: <%s>, <%s>\n",
|
|
|
|
pretty->bv_val, normal->bv_val, 0 );
|
|
|
|
|
|
|
|
return LDAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2001-12-23 09:19:46 +08:00
|
|
|
/*
|
2001-12-24 14:00:02 +08:00
|
|
|
* dnMatch routine
|
2001-12-23 09:19:46 +08:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
dnMatch(
|
|
|
|
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 ) {
|
2001-12-25 04:42:05 +08:00
|
|
|
match = strcmp( value->bv_val, asserted->bv_val );
|
2001-12-23 09:19:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NEW_LOGGING
|
|
|
|
LDAP_LOG(( "schema", LDAP_LEVEL_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 );
|
2001-12-23 08:43:57 +08:00
|
|
|
#endif
|
2001-12-08 14:57:06 +08:00
|
|
|
|
2001-12-23 09:19:46 +08:00
|
|
|
*matchp = match;
|
|
|
|
return( LDAP_SUCCESS );
|
|
|
|
}
|
|
|
|
|
2002-01-18 06:36:53 +08:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
dnParent(
|
|
|
|
const char *dn,
|
|
|
|
const char **pdn )
|
|
|
|
{
|
|
|
|
const char *p;
|
|
|
|
|
|
|
|
p = strchr( dn, ',' );
|
|
|
|
|
|
|
|
/* one-level dn */
|
|
|
|
if ( p == NULL ) {
|
|
|
|
*pdn = "";
|
|
|
|
return LDAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert( DN_SEPARATOR( p[ 0 ] ) );
|
|
|
|
p++;
|
|
|
|
|
|
|
|
assert( ATTR_LEADCHAR( p[ 0 ] ) );
|
|
|
|
*pdn = p;
|
|
|
|
|
|
|
|
return LDAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2001-12-24 12:39:15 +08:00
|
|
|
#ifdef SLAP_DN_MIGRATION
|
|
|
|
/*
|
|
|
|
* these routines are provided for migration purposes only!
|
|
|
|
* dn_normalize is deprecated in favor of dnNormalize
|
|
|
|
* strcmp/strcasecmp for DNs is deprecated in favor of dnMatch
|
|
|
|
*
|
|
|
|
* other routines are likewise deprecated but may not yet have
|
|
|
|
* replacement functions.
|
|
|
|
*/
|
|
|
|
|
2001-07-22 06:44:55 +08:00
|
|
|
/*
|
|
|
|
* dn_normalize - put dn into a canonical form suitable for storing
|
|
|
|
* in a hash database. this involves normalizing the case as well as
|
|
|
|
* the format. the dn is normalized in place as well as returned if valid.
|
2001-12-24 14:00:02 +08:00
|
|
|
* Deprecated in favor of dnNormalize()
|
dn_validate/dn_normalize has been rewritten by
David A. Cooper <david.cooper@nist.gov> (ITS#1232)
according to draft-ietf-ldapbis-dn-05.txt
A copyright statement follows:
The functions normalize_unicode(), get_hexpair(), write_hex_pair(),
get_next_byte(), get_next_char(), get_ber_length(),
ber_parse_primitive_string(), ber_parse_string(), String_normalize(),
DirectoryString_normalize(), PrintableString_normalize(),
IA5String_normalize(), ber_parse_primitive_bitstring(),
ber_parse_bitstring(), getNext8bits(), bitString_normalize(), match_oid(),
match_key(), get_validated_av_in_dn(), get_validated_rdn_in_dn(),
and get_validated_dn() in this file were developed at the National Institute
of Standards and Technology by employees of the Federal Government in the
course of their official duties. Pursuant to title 17 Section 105 of the
United States Code the code in these functions is not subject to copyright
protection and is in the public domain. The copyright for all other code in
this file is as specified below.
2001-07-13 16:21:14 +08:00
|
|
|
*/
|
2001-07-22 06:44:55 +08:00
|
|
|
char *
|
|
|
|
dn_normalize( char *dn )
|
|
|
|
{
|
2001-12-25 02:38:20 +08:00
|
|
|
struct berval val;
|
|
|
|
struct berval *normalized = NULL;
|
2001-12-05 04:22:26 +08:00
|
|
|
int rc;
|
|
|
|
|
2001-12-24 12:39:15 +08:00
|
|
|
if ( dn == NULL || dn[0] == '\0' ) {
|
|
|
|
return dn;
|
2001-12-05 04:22:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
val.bv_val = dn;
|
|
|
|
val.bv_len = strlen( dn );
|
|
|
|
|
|
|
|
rc = dnNormalize( NULL, &val, &normalized );
|
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
2001-12-24 12:39:15 +08:00
|
|
|
return NULL;
|
2001-12-05 04:22:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( val.bv_len < normalized->bv_len ) {
|
|
|
|
ber_bvfree( normalized );
|
2001-12-24 12:39:15 +08:00
|
|
|
return NULL;
|
2001-12-05 04:22:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
AC_MEMCPY( dn, normalized->bv_val, normalized->bv_len + 1 );
|
|
|
|
ber_bvfree( normalized );
|
|
|
|
|
2001-12-24 12:39:15 +08:00
|
|
|
return dn;
|
2001-12-05 04:22:26 +08:00
|
|
|
}
|
|
|
|
|
1998-08-09 08:43:13 +08:00
|
|
|
/*
|
2001-12-08 18:37:42 +08:00
|
|
|
* dn_parent - return the dn's parent, in-place
|
2001-12-24 23:48:35 +08:00
|
|
|
* FIXME: should be replaced by dnParent()
|
1998-08-09 08:43:13 +08:00
|
|
|
*/
|
|
|
|
char *
|
2001-12-08 18:37:42 +08:00
|
|
|
dn_parent(
|
2001-12-24 23:48:35 +08:00
|
|
|
Backend *be,
|
2001-12-08 14:57:06 +08:00
|
|
|
const char *dn )
|
1998-08-09 08:43:13 +08:00
|
|
|
{
|
2001-12-24 23:48:35 +08:00
|
|
|
const char *pdn;
|
|
|
|
|
|
|
|
if ( dn == NULL ) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( dn[ 0 ] != '\0' && ASCII_SPACE( dn[ 0 ] ) ) {
|
|
|
|
dn++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( dn[ 0 ] == '\0' ) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( be != NULL && be_issuffix( be, dn ) ) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( dnParent( dn, &pdn ) != LDAP_SUCCESS ) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ( char * )pdn;
|
2001-12-08 16:41:39 +08:00
|
|
|
}
|
2002-01-16 11:01:19 +08:00
|
|
|
#endif /* SLAP_DN_MIGRATION */
|
|
|
|
|
2001-12-08 16:41:39 +08:00
|
|
|
|
2001-12-24 23:48:35 +08:00
|
|
|
int
|
|
|
|
dnExtractRdn(
|
2001-12-28 01:17:01 +08:00
|
|
|
struct berval *dn,
|
2001-12-28 18:04:53 +08:00
|
|
|
struct berval *rdn )
|
2001-12-24 23:48:35 +08:00
|
|
|
{
|
|
|
|
LDAPRDN *tmpRDN;
|
|
|
|
const char *p;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
assert( dn );
|
|
|
|
assert( rdn );
|
|
|
|
|
2001-12-28 01:17:01 +08:00
|
|
|
if( dn->bv_len == 0 ) {
|
|
|
|
return LDAP_OTHER;
|
|
|
|
}
|
|
|
|
|
2002-01-10 02:18:36 +08:00
|
|
|
rc = ldap_str2rdn( dn->bv_val, &tmpRDN, (char **)&p, LDAP_DN_FORMAT_LDAP );
|
2001-12-24 23:48:35 +08:00
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2001-12-28 18:04:53 +08:00
|
|
|
rc = ldap_rdn2bv( tmpRDN, rdn, LDAP_DN_FORMAT_LDAPV3 );
|
2001-12-24 23:48:35 +08:00
|
|
|
ldap_rdnfree( tmpRDN );
|
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return LDAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2002-01-15 15:29:15 +08:00
|
|
|
* FIXME: should be replaced by dnExtractRdn()
|
2001-12-24 23:48:35 +08:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
dn_rdnlen(
|
|
|
|
Backend *be,
|
2001-12-28 16:38:24 +08:00
|
|
|
struct berval *dn_in )
|
1999-01-29 05:40:04 +08:00
|
|
|
{
|
2001-12-28 20:50:48 +08:00
|
|
|
int rc;
|
2001-12-28 23:13:16 +08:00
|
|
|
const char *p;
|
2001-12-24 23:48:35 +08:00
|
|
|
|
|
|
|
assert( dn_in );
|
|
|
|
|
|
|
|
if ( dn_in == NULL ) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-12-28 16:38:24 +08:00
|
|
|
if ( !dn_in->bv_len ) {
|
2001-12-24 23:48:35 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-12-28 16:38:24 +08:00
|
|
|
if ( be != NULL && be_issuffix( be, dn_in->bv_val ) ) {
|
2001-12-24 23:48:35 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-01-10 02:18:36 +08:00
|
|
|
rc = ldap_str2rdn( dn_in->bv_val, NULL, (char **)&p,
|
2001-12-28 20:50:48 +08:00
|
|
|
LDAP_DN_FORMAT_LDAP | LDAP_DN_SKIP );
|
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
2001-12-24 23:48:35 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-12-28 20:50:48 +08:00
|
|
|
return p - dn_in->bv_val;
|
1999-01-29 05:40:04 +08:00
|
|
|
}
|
|
|
|
|
2001-07-06 20:22:01 +08:00
|
|
|
|
2001-12-27 15:13:13 +08:00
|
|
|
/* rdnValidate:
|
2001-07-22 07:45:04 +08:00
|
|
|
*
|
2001-12-27 15:13:13 +08:00
|
|
|
* LDAP_SUCCESS if rdn is a legal rdn;
|
|
|
|
* LDAP_INVALID_SYNTAX otherwise (including a sequence of rdns)
|
2001-07-05 16:40:40 +08:00
|
|
|
*/
|
|
|
|
int
|
2001-12-27 15:13:13 +08:00
|
|
|
rdnValidate( struct berval *rdn )
|
1999-07-23 01:14:42 +08:00
|
|
|
{
|
2001-12-27 15:13:13 +08:00
|
|
|
#if 1
|
|
|
|
/* Major cheat!
|
|
|
|
* input is a pretty or normalized DN
|
|
|
|
* hence, we can just search for ','
|
|
|
|
*/
|
|
|
|
if( rdn == NULL || rdn->bv_len == 0 ) {
|
|
|
|
return LDAP_INVALID_SYNTAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
return strchr( rdn->bv_val, ',' ) == NULL
|
|
|
|
? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
|
|
|
|
|
|
|
|
#else
|
2001-12-25 02:42:51 +08:00
|
|
|
LDAPRDN *RDN, **DN[ 2 ] = { &RDN, NULL };
|
|
|
|
const char *p;
|
|
|
|
int rc;
|
2001-07-05 16:40:40 +08:00
|
|
|
|
2001-12-25 02:42:51 +08:00
|
|
|
/*
|
|
|
|
* must be non-empty
|
|
|
|
*/
|
|
|
|
if ( rdn == NULL || rdn == '\0' ) {
|
|
|
|
return 0;
|
2001-07-05 16:40:40 +08:00
|
|
|
}
|
|
|
|
|
2001-12-25 02:42:51 +08:00
|
|
|
/*
|
|
|
|
* must be parsable
|
|
|
|
*/
|
2002-01-10 02:18:36 +08:00
|
|
|
rc = ldap_str2rdn( rdn, &RDN, (char **)&p, LDAP_DN_FORMAT_LDAP );
|
2001-12-25 02:42:51 +08:00
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
|
|
return 0;
|
2001-07-05 16:40:40 +08:00
|
|
|
}
|
|
|
|
|
2001-12-25 02:42:51 +08:00
|
|
|
/*
|
|
|
|
* Must be one-level
|
|
|
|
*/
|
|
|
|
if ( p[ 0 ] != '\0' ) {
|
|
|
|
return 0;
|
2001-07-05 16:40:40 +08:00
|
|
|
}
|
|
|
|
|
2001-12-25 02:42:51 +08:00
|
|
|
/*
|
|
|
|
* Schema-aware validate
|
|
|
|
*/
|
|
|
|
if ( rc == LDAP_SUCCESS ) {
|
|
|
|
rc = LDAPDN_validate( DN );
|
2001-07-05 16:40:40 +08:00
|
|
|
}
|
2001-12-25 02:42:51 +08:00
|
|
|
ldap_rdnfree( RDN );
|
2001-07-05 16:40:40 +08:00
|
|
|
|
2001-12-25 02:42:51 +08:00
|
|
|
/*
|
|
|
|
* Must validate (there's a repeated parsing ...)
|
|
|
|
*/
|
|
|
|
return ( rc == LDAP_SUCCESS );
|
2001-12-27 15:13:13 +08:00
|
|
|
#endif
|
1999-07-23 01:14:42 +08:00
|
|
|
}
|
1999-03-25 04:26:43 +08:00
|
|
|
|
|
|
|
|
|
|
|
/* build_new_dn:
|
|
|
|
*
|
2001-07-22 07:45:04 +08:00
|
|
|
* Used by ldbm/bdb2 back_modrdn to create the new dn of entries being
|
1999-03-25 04:26:43 +08:00
|
|
|
* renamed.
|
|
|
|
*
|
2001-12-25 02:42:51 +08:00
|
|
|
* new_dn = parent (p_dn) + separator + rdn (newrdn) + null.
|
1999-03-25 04:26:43 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
2001-12-27 08:58:14 +08:00
|
|
|
build_new_dn( struct berval * new_dn,
|
|
|
|
struct berval * parent_dn,
|
|
|
|
struct berval * newrdn )
|
1999-03-25 04:26:43 +08:00
|
|
|
{
|
2001-12-27 00:25:18 +08:00
|
|
|
char *ptr;
|
1999-03-25 05:45:15 +08:00
|
|
|
|
2001-12-25 00:53:47 +08:00
|
|
|
if ( parent_dn == NULL ) {
|
2001-12-27 08:58:14 +08:00
|
|
|
ber_dupbv( new_dn, newrdn );
|
2001-07-22 07:45:04 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-12-27 08:58:14 +08:00
|
|
|
new_dn->bv_len = parent_dn->bv_len + newrdn->bv_len + 1;
|
|
|
|
new_dn->bv_val = (char *) ch_malloc( new_dn->bv_len + 1 );
|
1999-03-25 04:26:43 +08:00
|
|
|
|
2001-12-27 08:58:14 +08:00
|
|
|
ptr = slap_strcopy( new_dn->bv_val, newrdn->bv_val );
|
2001-12-27 00:25:18 +08:00
|
|
|
*ptr++ = ',';
|
2001-12-27 08:58:14 +08:00
|
|
|
strcpy( ptr, parent_dn->bv_val );
|
1999-07-23 01:14:42 +08:00
|
|
|
}
|
2001-12-24 12:39:15 +08:00
|
|
|
|
2001-12-24 14:00:02 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* dnIsSuffix - tells whether suffix is a suffix of dn.
|
|
|
|
* Both dn and suffix must be normalized.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
dnIsSuffix(
|
|
|
|
const struct berval *dn,
|
|
|
|
const struct berval *suffix )
|
|
|
|
{
|
|
|
|
int d = dn->bv_len - suffix->bv_len;
|
|
|
|
|
|
|
|
assert( dn );
|
|
|
|
assert( suffix );
|
|
|
|
|
|
|
|
/* empty suffix matches any dn */
|
|
|
|
if ( suffix->bv_len == 0 ) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* suffix longer than dn */
|
|
|
|
if ( d < 0 ) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no rdn separator or escaped rdn separator */
|
|
|
|
if ( d > 1 && ( !DN_SEPARATOR( dn->bv_val[ d - 1 ] )
|
|
|
|
|| DN_ESCAPE( dn->bv_val[ d - 2 ] ) ) ) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no possible match or malformed dn */
|
|
|
|
if ( d == 1 ) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* compare */
|
|
|
|
return( strcmp( dn->bv_val + d, suffix->bv_val ) == 0 );
|
|
|
|
}
|