summaryrefslogtreecommitdiffstats
path: root/ldap/servers/slapd/dn.c
diff options
context:
space:
mode:
authorNoriko Hosoi <nhosoi@redhat.com>2009-01-06 22:50:30 +0000
committerNoriko Hosoi <nhosoi@redhat.com>2009-01-06 22:50:30 +0000
commit3d9bdf5a15fcb3df6822aa9054e70d80ced07087 (patch)
treedd47111eca4e992f8722493adea232f6d1635722 /ldap/servers/slapd/dn.c
parentb549731422b37541cfd007d7ec09e9b1482413cf (diff)
downloadds-3d9bdf5a15fcb3df6822aa9054e70d80ced07087.tar.gz
ds-3d9bdf5a15fcb3df6822aa9054e70d80ced07087.tar.xz
ds-3d9bdf5a15fcb3df6822aa9054e70d80ced07087.zip
Resolves: #438139
Summary: DN with antislash('\') rename (modrdn) problem Problem description: Unescape codes in the DS (strcpy_special_undo in ava.c and strcpy_unescape_dnvalue in dn.c) were "unescaping" more than the escape code (e.g., escape_dn_value in NET LDAP) does escaping. The test string 'BeforeSlash\AfterSlash' fortunately/unfortunately contains '\Af', which is considered '\##' (where # is hex number) by the DS unescape functions even though it was not meant to be escaped. As long as using UTF-8, there is no chance for the server to receive "\af". Change description: 1) There were identical static functions: strcpy_special_undo (ava.c) and strcpy_special_undo (dn.c). Merged them to strcpy_unescape_value and put it in util.c. 2) In the unescape/normalize functions for dn (strcpy_unescape_value in util.c and substr_dn_normalize in dn.c), added a check for the first hex number in '\##'. If the 8th bit is on, we don't do unescaping but store it as is since the unescaped character is not UTF-8. 3) If 2 consecutive '\'s are passed to the unescape/normalize functions, keep one of them.
Diffstat (limited to 'ldap/servers/slapd/dn.c')
-rw-r--r--ldap/servers/slapd/dn.c256
1 files changed, 98 insertions, 158 deletions
diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c
index 45cf142c..6aa7ae7b 100644
--- a/ldap/servers/slapd/dn.c
+++ b/ldap/servers/slapd/dn.c
@@ -138,11 +138,11 @@ hexchar2int( char c )
char *
substr_dn_normalize( char *dn, char *end )
{
- /* \xx is changed to \c.
- * \c is changed to c, unless this would change its meaning.
- * All values that contain 2 or more separators are "enquoted";
- * all other values are not enquoted.
- */
+ /* \xx is changed to \c.
+ * \c is changed to c, unless this would change its meaning.
+ * All values that contain 2 or more separators are "enquoted";
+ * all other values are not enquoted.
+ */
char *value = NULL;
char *value_separator = NULL;
char *d = NULL;
@@ -192,22 +192,22 @@ substr_dn_normalize( char *dn, char *end )
break;
case INVALUE:
if ( gotesc ) {
- if ( SEPARATOR( *s ) ) {
- value_separator = d;
- } else if ( ! NEEDSESCAPE( *s ) ) {
- --d; /* eliminate the \ */
- }
+ if ( SEPARATOR( *s ) ) {
+ value_separator = d;
+ } else if ( ! NEEDSESCAPE( *s ) ) {
+ --d; /* eliminate the \ */
+ }
} else if ( SEPARATOR( *s ) ) {
- while ( SPACE( *(d - 1) ) )
- d--;
- if ( value_separator == dn ) { /* 2 or more separators */
+ while ( SPACE( *(d - 1) ) )
+ d--;
+ if ( value_separator == dn ) { /* 2 or more separators */
/* convert to quoted value: */
char *L = NULL; /* char after last seperator */
char *R; /* value character iterator */
int escape_skips = 0; /* number of escapes we have seen after the first */
for ( R = value; (R = strchr( R, '\\' )) && (R < d); L = ++R ) {
- if ( SEPARATOR( R[1] )) {
+ if ( SEPARATOR( R[1] )) {
if ( L == NULL ) {
/* executes once, at first escape, adds opening quote */
const size_t len = R - value;
@@ -229,113 +229,120 @@ substr_dn_normalize( char *dn, char *end )
--d;
++escape_skips;
}
- }
+ }
}
memmove( value, L, d - L + escape_skips );
*d++ = '"'; /* closing quote */
- }
- state = B4TYPE;
-
- /*
- * Track and sort attribute values within
- * multivalued RDNs.
- */
- if ( *s == '+' || rdn_av_count > 0 ) {
+ }
+ state = B4TYPE;
+
+ /*
+ * Track and sort attribute values within
+ * multivalued RDNs.
+ */
+ if ( *s == '+' || rdn_av_count > 0 ) {
add_rdn_av( typestart, d, &rdn_av_count,
&rdn_avs, initial_rdn_av_stack );
- }
- if ( *s != '+' ) { /* at end of this RDN */
+ }
+ if ( *s != '+' ) { /* at end of this RDN */
if ( rdn_av_count > 1 ) {
- sort_rdn_avs( rdn_avs, rdn_av_count );
+ sort_rdn_avs( rdn_avs, rdn_av_count );
}
if ( rdn_av_count > 0 ) {
- reset_rdn_avs( &rdn_avs, &rdn_av_count );
+ reset_rdn_avs( &rdn_avs, &rdn_av_count );
}
- }
+ }
- *d++ = (*s == '+') ? '+' : ',';
- break;
+ *d++ = (*s == '+') ? '+' : ',';
+ break;
}
*d++ = *s;
break;
case INQUOTEDVALUE:
if ( gotesc ) {
- if ( ! NEEDSESCAPE( *s ) ) {
- --d; /* eliminate the \ */
- }
+ if ( ! NEEDSESCAPE( *s ) ) {
+ --d; /* eliminate the \ */
+ }
} else if ( *s == '"' ) {
- state = B4SEPARATOR;
- if ( value_separator == dn /* 2 or more separators */
- || SPACE( value[1] ) || SPACE( d[-1] ) ) {
- *d++ = *s;
- } else {
- /* convert to non-quoted value: */
- if ( value_separator == NULL ) { /* no separators */
- memmove ( value, value+1, (d-value)-1 );
- --d;
- } else { /* 1 separator */
- memmove ( value, value+1, (value_separator-value)-1 );
- *(value_separator - 1) = '\\';
+ state = B4SEPARATOR;
+ if ( value_separator == dn /* 2 or more separators */
+ || SPACE( value[1] ) || SPACE( d[-1] ) ) {
+ *d++ = *s;
+ } else {
+ /* convert to non-quoted value: */
+ if ( value_separator == NULL ) { /* no separators */
+ memmove ( value, value+1, (d-value)-1 );
+ --d;
+ } else { /* 1 separator */
+ memmove ( value, value+1, (value_separator-value)-1 );
+ *(value_separator - 1) = '\\';
+ }
}
- }
- break;
+ break;
}
if ( SEPARATOR( *s )) {
- if ( value_separator ) value_separator = dn;
- else value_separator = d;
+ if ( value_separator ) value_separator = dn;
+ else value_separator = d;
}
*d++ = *s;
break;
case B4SEPARATOR:
if ( SEPARATOR( *s ) ) {
- state = B4TYPE;
-
- /*
- * Track and sort attribute values within
- * multivalued RDNs.
- */
- if ( *s == '+' || rdn_av_count > 0 ) {
- add_rdn_av( typestart, d, &rdn_av_count,
- &rdn_avs, initial_rdn_av_stack );
- }
- if ( *s != '+' ) { /* at end of this RDN */
- if ( rdn_av_count > 1 ) {
- sort_rdn_avs( rdn_avs, rdn_av_count );
+ state = B4TYPE;
+
+ /*
+ * Track and sort attribute values within
+ * multivalued RDNs.
+ */
+ if ( *s == '+' || rdn_av_count > 0 ) {
+ add_rdn_av( typestart, d, &rdn_av_count,
+ &rdn_avs, initial_rdn_av_stack );
}
- if ( rdn_av_count > 0 ) {
- reset_rdn_avs( &rdn_avs, &rdn_av_count );
+ if ( *s != '+' ) { /* at end of this RDN */
+ if ( rdn_av_count > 1 ) {
+ sort_rdn_avs( rdn_avs, rdn_av_count );
+ }
+ if ( rdn_av_count > 0 ) {
+ reset_rdn_avs( &rdn_avs, &rdn_av_count );
+ }
}
- }
- *d++ = (*s == '+') ? '+' : ',';
+ *d++ = (*s == '+') ? '+' : ',';
}
break;
default:
LDAPDebug( LDAP_DEBUG_ANY,
- "slapi_dn_normalize - unknown state %d\n", state, 0, 0 );
+ "slapi_dn_normalize - unknown state %d\n", state, 0, 0 );
break;
}
- if ( *s != '\\' ) {
- gotesc = 0;
- } else {
- gotesc = 1;
- if ( s+2 < end ) {
- int n = hexchar2int( s[1] );
- if ( n >= 0 ) {
- int n2 = hexchar2int( s[2] );
- if ( n2 >= 0 ) {
- n = (n << 4) + n2;
- if (n == 0) { /* don't change \00 */
- *d++ = *++s;
- *d++ = *++s;
- gotesc = 0;
- } else { /* change \xx to a single char */
- ++s;
- *(unsigned char*)(s+1) = n;
- }
+ if ( *s == '\\' ) {
+ if ( gotesc ) { /* '\\', again */
+ /* <type>=XXX\\\\7AYYY; we should keep \\\\. */
+ gotesc = 0;
+ } else {
+ gotesc = 1;
+ if ( s+2 < end ) {
+ int n = hexchar2int( s[1] );
+ /* If 8th bit is on, the char is not ASCII (not UTF-8).
+ * Thus, not UTF-8 */
+ if ( n >= 0 && n < 8 ) {
+ int n2 = hexchar2int( s[2] );
+ if ( n2 >= 0 ) {
+ n = (n << 4) + n2;
+ if (n == 0) { /* don't change \00 */
+ *d++ = *++s;
+ *d++ = *++s;
+ gotesc = 0;
+ } else { /* change \xx to a single char */
+ ++s;
+ *(unsigned char*)(s+1) = n;
+ }
+ }
+ }
}
- }
}
+ } else {
+ gotesc = 0;
}
}
@@ -349,14 +356,14 @@ substr_dn_normalize( char *dn, char *end )
* or B4SEPARATOR state if we have a valid rdn component to
* be added. */
if ((rdn_av_count > 0) && ((state == INVALUE) || (state == B4SEPARATOR))) {
- add_rdn_av( typestart, d, &rdn_av_count,
- &rdn_avs, initial_rdn_av_stack );
+ add_rdn_av( typestart, d, &rdn_av_count,
+ &rdn_avs, initial_rdn_av_stack );
}
if ( rdn_av_count > 1 ) {
- sort_rdn_avs( rdn_avs, rdn_av_count );
+ sort_rdn_avs( rdn_avs, rdn_av_count );
}
if ( rdn_av_count > 0 ) {
- reset_rdn_avs( &rdn_avs, &rdn_av_count );
+ reset_rdn_avs( &rdn_avs, &rdn_av_count );
}
/* Trim trailing spaces */
while ( d != dn && *(d - 1) == ' ' ) d--; /* XXX 518524 */
@@ -793,73 +800,6 @@ slapi_is_rootdse( const char *dn )
return 0;
}
-
-
-/*
-** This function takes a quoted attribute value of the form "abc",
-** and strips off the enclosing quotes. It also deals with quoted
-** characters by removing the preceeding '\' character.
-**
-*/
-static void
-strcpy_unescape_dnvalue( char *d, const char *s )
-{
- const char *end = s + strlen(s);
- for ( ; *s; s++ )
- {
- switch ( *s )
- {
- case '"':
- break;
- case '\\':
- {
- /*
- * The '\' could be escaping a single character, ie \"
- * or could be escaping a hex byte, ie \01
- */
- int singlecharacter= 1;
- if ( s+2 < end )
- {
- int n = hexchar2int( s[1] );
- if ( n >= 0 )
- {
- int n2 = hexchar2int( s[2] );
- if ( n2 >= 0 )
- {
- singlecharacter= 0;
- n = (n << 4) + n2;
- if (n == 0)
- {
- /* don't change \00 */
- *d++ = *++s;
- *d++ = *++s;
- }
- else
- {
- /* change \xx to a single char */
- ++s;
- *(unsigned char*)(s+1) = n;
- }
- }
- }
- }
- if(singlecharacter)
- {
- s++;
- *d++ = *s;
- }
- break;
- }
- default:
- *d++ = *s;
- break;
- }
- }
- *d = '\0';
-}
-
-
-
int
slapi_rdn2typeval(
char *rdn,
@@ -881,7 +821,7 @@ slapi_rdn2typeval(
When adding the rdn attribute in the entry, we need to remove
all special escaped characters included in the value itself,
i.e., strings like "\;" must be converted to ";" and so on... */
- strcpy_unescape_dnvalue(s,s);
+ strcpy_unescape_value(s,s);
bv->bv_val = s;
bv->bv_len = strlen( s );