*/
#include "portable.h"
+#include <stdlib.h>
+
#include <ac/stdlib.h>
#include <ac/string.h>
+#include <ac/unistd.h>
#include <stdio.h>
#include <ldap.h>
+
+#include "ldap-int.h"
+
#include "ldif.h"
#include "lutil.h"
#include "lutil_ldap.h"
#include "ldap_defaults.h"
int
-main(int argc, char *argv[])
+main( int argc, char *argv[] )
{
- int rc, i, debug = -1;
+ int rc, i, debug = 0, f2 = 0;
unsigned flags[ 2 ] = { 0U, 0U };
- char *str, buf[1024];
+ char *strin, *str, *str2, buf[ 1024 ];
LDAPDN *dn = NULL;
- if (argc < 2) {
- fprintf(stderr, "usage: dntest <dn> [flags-in[,...]] [flags-out[,...]]\n\n");
- fprintf(stderr, "\tflags-in: V3,V2,DCE,PEDANTIC\n");
- fprintf(stderr, "\tflags-out: V3,V2,UFN,DCE,AD,PEDANTIC\n\n");
- return 0;
+ while ( 1 ) {
+ int opt = getopt( argc, argv, "d:" );
+
+ if ( opt == EOF ) {
+ break;
+ }
+
+ switch ( opt ) {
+ case 'd':
+ debug = atoi( optarg );
+ break;
+ }
}
- if (ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &debug) != LBER_OPT_SUCCESS) {
- fprintf(stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug);
+ optind--;
+ argc -= optind;
+ argv += optind;
+
+ if ( argc < 2 ) {
+ fprintf( stderr, "usage: dntest <dn> [flags-in[,...]] [flags-out[,...]]\n\n" );
+ fprintf( stderr, "\tflags-in: V3,V2,DCE,PEDANTIC\n" );
+ fprintf( stderr, "\tflags-out: V3,V2,UFN,DCE,AD,PEDANTIC\n\n" );
+ return( 0 );
}
- if (ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &debug) != LDAP_OPT_SUCCESS) {
- fprintf(stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug);
+
+ if ( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) {
+ fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
+ }
+ if ( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) {
+ fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
}
- if ( strcmp(argv[1], "-") == 0) {
+ if ( strcmp( argv[ 1 ], "-" ) == 0 ) {
size_t len;
- fgets(buf, sizeof(buf), stdin);
- len = strlen(buf)-1;
- if (len >= 0 && buf[len] == '\n') {
- buf[len] = '\0';
+ fgets( buf, sizeof( buf ), stdin );
+ len = strlen( buf ) - 1;
+ if ( len >= 0 && buf[ len ] == '\n' ) {
+ buf[ len ] = '\0';
}
- str = buf;
+ strin = buf;
} else {
- str = argv[1];
+ strin = argv[ 1 ];
}
- if (argc >= 3) {
- for ( i = 0; i < argc-2; i++ ) {
+ if ( argc >= 3 ) {
+ for ( i = 0; i < argc - 2; i++ ) {
char *s, *e;
- for (s = argv[2+i]; s; s = e) {
- e = strchr(s, ',');
- if (e != NULL) {
- e[0] = '\0';
+ for ( s = argv[ 2 + i ]; s; s = e ) {
+ e = strchr( s, ',' );
+ if ( e != NULL ) {
+ e[ 0 ] = '\0';
e++;
}
- if (!strcasecmp(s, "V3")) {
- flags[i] |= LDAP_DN_FORMAT_LDAPV3;
- } else if (!strcasecmp(s, "V2")) {
- flags[i] |= LDAP_DN_FORMAT_LDAPV2;
- } else if (!strcasecmp(s, "DCE")) {
- flags[i] |= LDAP_DN_FORMAT_DCE;
- } else if (!strcasecmp(s, "UFN")) {
- flags[i] |= LDAP_DN_FORMAT_UFN;
- } else if (!strcasecmp(s, "AD")) {
- flags[i] |= LDAP_DN_FORMAT_AD_CANONICAL;
- } else if (!strcasecmp(s, "PEDANTIC")) {
- flags[i] |= LDAP_DN_PEDANTIC;
+ if ( !strcasecmp( s, "V3" ) ) {
+ flags[ i ] |= LDAP_DN_FORMAT_LDAPV3;
+ } else if ( !strcasecmp( s, "V2" ) ) {
+ flags[ i ] |= LDAP_DN_FORMAT_LDAPV2;
+ } else if ( !strcasecmp( s, "DCE" ) ) {
+ flags[ i ] |= LDAP_DN_FORMAT_DCE;
+ } else if ( !strcasecmp( s, "UFN" ) ) {
+ flags[ i ] |= LDAP_DN_FORMAT_UFN;
+ } else if ( !strcasecmp( s, "AD" ) ) {
+ flags[ i ] |= LDAP_DN_FORMAT_AD_CANONICAL;
+ } else if ( !strcasecmp( s, "PEDANTIC" ) ) {
+ flags[ i ] |= LDAP_DN_PEDANTIC;
}
}
}
}
-
- rc = ldap_str2dn(str, &dn, flags[0]);
+
+ f2 = argc > 3 ? 1 : 0;
+
+ rc = ldap_str2dn( strin, &dn, flags[ 0 ] );
if ( rc == LDAP_SUCCESS &&
- ldap_dn2str( dn, &str, flags[argc > 3 ? 1 : 0] )
- == LDAP_SUCCESS ) {
- fprintf( stdout, "%s\n", str );
+ ldap_dn2str( dn, &str, flags[ f2 ] ) == LDAP_SUCCESS ) {
+ char **values, *tmp, *tmp2;
+ int n;
+
+ switch ( flags[ f2 ] & LDAP_DN_FORMAT_MASK ) {
+ case LDAP_DN_FORMAT_UFN:
+ case LDAP_DN_FORMAT_AD_CANONICAL:
+ return( 0 );
+
+ case LDAP_DN_FORMAT_LDAPV3:
+ case LDAP_DN_FORMAT_LDAPV2:
+ fprintf( stdout, "\nldap_dn2str(ldap_str2dn(\"%s\"))\n"
+ "\t=\"%s\"\n", strin, str );
+ tmp = ldap_dn2ufn( strin );
+ fprintf( stdout, "\nldap_dn2ufn(\"%s\")\n\t=\"%s\"\n",
+ strin, tmp );
+ ldap_memfree( tmp );
+ tmp = ldap_dn2dcedn( strin );
+ fprintf( stdout, "\nldap_dn2dcedn(\"%s\")\n"
+ "\t=\"%s\"\n", strin, tmp );
+ tmp2 = ldap_dcedn2dn( tmp );
+ fprintf( stdout, "\nldap_dcedn2dn(\"%s\")\n"
+ "\t=\"%s\"\n", tmp, tmp2 );
+ ldap_memfree( tmp );
+ ldap_memfree( tmp2 );
+ tmp = ldap_dn2ad_canonical( strin );
+ fprintf( stdout, "\nldap_dn2ad_canonical(\"%s\")\n"
+ "\t=\"%s\"\n", strin, tmp );
+ ldap_memfree( tmp );
+
+ fprintf( stdout, "\nldap_explode_dn(\"%s\"):\n", str );
+ values = ldap_explode_dn( str, 0 );
+ for ( n = 0; values && values[ n ]; n++ ) {
+ char **vv;
+ int nn;
+
+ fprintf( stdout, "\t\"%s\"\n", values[ n ] );
+
+ fprintf( stdout, "\tldap_explode_rdn(\"%s\")\n",
+ values[ n ] );
+ vv = ldap_explode_rdn( values[ n ], 0 );
+ for ( nn = 0; vv && vv[ nn ]; nn++ ) {
+ fprintf( stdout, "\t\t'%s'\n",
+ vv[ nn ] );
+ }
+ LDAP_VFREE( vv );
+
+ fprintf( stdout, "\tldap_explode_rdn(\"%s\")"
+ " (no types)\n", values[ n ] );
+ vv = ldap_explode_rdn( values[ n ], 1 );
+ for ( nn = 0; vv && vv[ nn ]; nn++ ) {
+ fprintf( stdout, "\t\t\t\"%s\"\n",
+ vv[ nn ] );
+ }
+ LDAP_VFREE( vv );
+
+ }
+ LDAP_VFREE( values );
+
+ fprintf( stdout, "\nldap_explode_dn(\"%s\")"
+ " (no types):\n", str );
+ values = ldap_explode_dn( str, 1 );
+ for ( n = 0; values && values[ n ]; n++ ) {
+ fprintf( stdout, "\t\"%s\"\n", values[ n ] );
+ }
+ LDAP_VFREE( values );
+
+ break;
+ }
+
+ rc = ldap_str2dn( str, &dn, flags[ f2 ] );
+ if ( rc == LDAP_SUCCESS &&
+ ldap_dn2str( dn, &str2, flags[ f2 ] )
+ == LDAP_SUCCESS ) {
+ fprintf( stdout, "\n\"%s\"\n\t == \"%s\" ? %s\n",
+ str, str2,
+ strcmp( str, str2 ) == 0 ? "yes" : "no" );
+ ldap_memfree( str2 );
+ }
+ ldap_memfree( str );
}
- return 0;
+ /* note: dn is not freed */
+
+ return( 0 );
}
#define NAME_TYPE_DCE_DN 2
static char **explode_name( const char *name, int notypes, int is_type );
+static char *dn2dn( const char *dnin, unsigned fin, unsigned fout );
+/* from libraries/libldap/schema.c */
+extern char * parse_numericoid(const char **sp, int *code, const int flags);
+
+/* parsing/printing routines */
+static int str2strval( const char *str, struct berval **val,
+ const char **next, unsigned flags, unsigned *retFlags );
+static int DCE2strval( const char *str, struct berval **val,
+ const char **next, unsigned flags );
+static int IA52strval( const char *str, struct berval **val,
+ const char **next, unsigned flags );
+static int quotedIA52strval( const char *str, struct berval **val,
+ const char **next, unsigned flags );
+static int hexstr2binval( const char *str, struct berval **val,
+ const char **next, unsigned flags );
+static int hexstr2bin( const char *str, char *c );
+static int byte2hexpair( const char *val, char *pair );
+static int binval2hexstr( struct berval *val, char *str );
+static ber_len_t strval2strlen( struct berval *val, unsigned flags );
+static int strval2str( struct berval *val, char *str, unsigned flags,
+ ber_len_t *len );
+static ber_len_t strval2IA5strlen( struct berval *val, unsigned flags );
+static int strval2IA5str( struct berval *val, char *str, unsigned flags,
+ ber_len_t *len );
+static ber_len_t strval2DCEstrlen( struct berval *val, unsigned flags );
+static int strval2DCEstr( struct berval *val, char *str, unsigned flags,
+ ber_len_t *len );
+static ber_len_t strval2ADstrlen( struct berval *val, unsigned flags );
+static int strval2ADstr( struct berval *val, char *str, unsigned flags,
+ ber_len_t *len );
+static int dn2domain( LDAPDN *dn, char **str, int *iRDN );
+
+/* AVA helpers */
+static LDAPAVA * ldapava_new( const char *attr, const struct berval *val,
+ unsigned flags );
+static void ldapava_free( LDAPAVA *ava );
+static LDAPRDN * ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava );
+static void ldapava_free_rdn( LDAPRDN *rdn );
+static LDAPDN * ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn );
+static LDAPDN * ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn );
+static void ldapava_free_dn( LDAPDN *dn );
+
+/* Higher level helpers */
+static ber_len_t rdn2strlen( LDAPRDN *rdn );
+static int rdn2str( LDAPRDN *rdn, char *str, ber_len_t *len );
+static ber_len_t rdn2UFNstrlen( LDAPRDN *rdn );
+static int rdn2UFNstr( LDAPRDN *rdn, char *str, ber_len_t *len );
+
+/* ? */
+int ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags );
+
+/*
+ * RFC 1823 ldap_get_dn
+ */
char *
ldap_get_dn( LDAP *ld, LDAPMessage *entry )
{
return( dn );
}
+/*
+ * RFC 1823 ldap_dn2ufn
+ */
char *
ldap_dn2ufn( LDAP_CONST char *dn )
{
+#ifndef USE_LDAP_DN_PARSING
char *ufn;
char **vals;
int i;
LDAP_VFREE( vals );
return ufn;
+#else /* USE_LDAP_DN_PARSING */
+ Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
+
+ return dn2dn( dn, LDAP_DN_FORMAT_LDAPV3, LDAP_DN_FORMAT_UFN );
+#endif /* USE_LDAP_DN_PARSING */
}
char **
ldap_explode_dn( LDAP_CONST char *dn, int notypes )
{
+#ifndef USE_LDAP_DN_PARSING
Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
return explode_name( dn, notypes, NAME_TYPE_LDAP_DN );
+#else /* USE_LDAP_DN_PARSING */
+ LDAPDN *tmpDN;
+ char **values = NULL;
+ int iRDN;
+ unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
+
+ Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
+
+ if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAPV3 )
+ != LDAP_SUCCESS ) {
+ return( NULL );
+ }
+
+ for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) {
+ char *str, **v = NULL;
+
+ ldap_rdn2str( tmpDN[ iRDN ][ 0 ], &str, flag );
+
+ v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iRDN ) );
+ if ( v == NULL ) {
+ LBER_VFREE( values );
+ ldapava_free_dn( tmpDN );
+ return( NULL );
+ }
+ values = v;
+ values[ iRDN ] = str;
+ }
+ values[ iRDN ] = NULL;
+
+ return( values );
+#endif /* USE_LDAP_DN_PARSING */
}
char **
ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
{
+#ifndef USE_LDAP_DN_PARSING
Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
+
return explode_name( rdn, notypes, NAME_TYPE_LDAP_RDN );
+#else /* USE_LDAP_DN_PARSING */
+ LDAPDN *tmpDN;
+ char **values = NULL;
+ int iAVA;
+ unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
+
+ Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
+
+ /*
+ * we assume this dn is made of one rdn only
+ */
+ if ( ldap_str2dn( rdn, &tmpDN, LDAP_DN_FORMAT_LDAPV3 )
+ != LDAP_SUCCESS ) {
+ return( NULL );
+ }
+
+ for ( iAVA = 0; tmpDN[ 0 ][ 0 ][ iAVA ]; iAVA++ ) {
+ ber_len_t l = 0, vl, al = 0;
+ char *str, **v = NULL;
+ LDAPAVA *ava = tmpDN[ 0 ][ 0 ][ iAVA ][ 0 ];
+
+ v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iAVA ) );
+ if ( v == NULL ) {
+ LBER_VFREE( values );
+ ldapava_free_dn( tmpDN );
+ return( NULL );
+ }
+ values = v;
+
+ if ( ava->la_flags == LDAP_AVA_BINARY ) {
+ vl = 1 + 2 * ava->la_value->bv_len;
+ } else {
+ vl = strval2strlen( ava->la_value, ava->la_flags );
+ }
+
+ if ( !notypes ) {
+ al = strlen( ava->la_attr );
+
+ l = vl + al + 1;
+
+ str = LDAP_MALLOC( l + 1 );
+ AC_MEMCPY( str, ava->la_attr, al );
+ str[ al++ ] = '=';
+ } else {
+ l = vl;
+ str = LDAP_MALLOC( l + 1 );
+ }
+
+ if ( ava->la_flags == LDAP_AVA_BINARY ) {
+ str[ al++ ] = '#';
+ binval2hexstr( ava->la_value, &str[ al ] );
+ } else {
+ strval2str( ava->la_value, &str[ al ],
+ ava->la_flags, &vl );
+ }
+
+ str[ l ] = '\0';
+ values[ iAVA ] = str;
+ }
+ values[ iAVA ] = NULL;
+
+ return( values );
+#endif /* USE_LDAP_DN_PARSING */
}
+char *
+ldap_dn2ad_canonical( LDAP_CONST char *dn )
+{
+ Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
+
+ return dn2dn( dn, LDAP_DN_FORMAT_LDAPV3, LDAP_DN_FORMAT_AD_CANONICAL );
+}
+
+static char *
+dn2dn( const char *dnin, unsigned fin, unsigned fout )
+{
+ char *dnout = NULL;
+ LDAPDN *tmpDN = NULL;
+
+ if( dnin == NULL ) {
+ return NULL;
+ }
+
+ if ( ldap_str2dn( dnin , &tmpDN, fin ) != LDAP_SUCCESS ) {
+ return NULL;
+ }
+
+ /* don't care about the result ... */
+ ldap_dn2str( tmpDN, &dnout, fout );
+
+ ldapava_free_dn( tmpDN );
+
+ return dnout;
+}
+
+
char *
ldap_dn2dcedn( LDAP_CONST char *dn )
{
+#ifndef USE_LDAP_DN_PARSING
char *dce, *q, **rdns, **p;
int len = 0;
strcpy( q, *p );
return dce;
+#else /* USE_LDAP_DN_PARSING */
+ Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
+
+ return dn2dn( dn, LDAP_DN_FORMAT_LDAPV3, LDAP_DN_FORMAT_DCE );
+#endif /* USE_LDAP_DN_PARSING */
}
char *
ldap_dcedn2dn( LDAP_CONST char *dce )
{
+#ifndef USE_LDAP_DN_PARSING
char *dn, *q, **rdns, **p;
int len;
}
return dn;
+#else /* USE_LDAP_DN_PARSING */
+ Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
+
+ return dn2dn( dce, LDAP_DN_FORMAT_DCE, LDAP_DN_FORMAT_LDAPV3 );
+#endif /* USE_LDAP_DN_PARSING */
}
#define INQUOTE 1
( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
#define LDAP_DN_FORMAT(f) ( (f) & LDAP_DN_FORMAT_MASK )
-/* from libraries/libldap/schema.c */
-extern char * parse_numericoid(const char **sp, int *code, const int flags);
-
-static int str2strval( const char *str, struct berval **val,
- const char **next, unsigned flags, unsigned *retFlags );
-static int DCE2strval( const char *str, struct berval **val,
- const char **next, unsigned flags );
-static int IA52strval( const char *str, struct berval **val,
- const char **next, unsigned flags );
-static int quotedIA52strval( const char *str, struct berval **val,
- const char **next, unsigned flags );
-static int hexstr2binval( const char *str, struct berval **val,
- const char **next, unsigned flags );
-static int hexstr2bin( const char *str, unsigned *c );
-static int byte2hexpair( const char *val, char *pair );
-static int binval2hexstr( struct berval *val, char *str );
-static ber_len_t strval2strlen( struct berval *val, unsigned flags );
-static int strval2str( struct berval *val, char *str, unsigned flags,
- ber_len_t *len );
-static ber_len_t strval2IA5strlen( struct berval *val, unsigned flags );
-static int strval2IA5str( struct berval *val, char *str, unsigned flags,
- ber_len_t *len );
-static ber_len_t strval2DCEstrlen( struct berval *val, unsigned flags );
-static int strval2DCEstr( struct berval *val, char *str, unsigned flags,
- ber_len_t *len );
-static ber_len_t strval2ADstrlen( struct berval *val, unsigned flags );
-static int strval2ADstr( struct berval *val, char *str, unsigned flags,
- ber_len_t *len );
-static int dn2domain( LDAPDN *dn, char **str, int *iRDN );
-
/*
* LDAPAVA helpers
*/
/* should we test it? */
if ( ava == NULL ) {
- return NULL;
+ return( NULL );
}
ava->la_attr = ( char * )attr;
ava->la_value = ( struct berval * )val;
ava->la_flags = flags;
- return ava;
+ return( ava );
}
static void
newRDN[ i ][ 0 ] = ava;
newRDN[ i + 1 ] = NULL;
- return newRDN;
+ return( newRDN );
}
static void
newDN[ i ][ 0 ] = rdn;
newDN[ i + 1 ] = NULL;
- return newDN;
+ return( newDN );
}
static LDAPDN *
newDN[ 0 ][ 0 ] = rdn;
newDN[ i + 1 ] = NULL;
- return newDN;
+ return( newDN );
}
static void
if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
/*
- * FIXME: RFC 2253 does not explicitly
+ * RFC 2253 does not explicitly
* allow lang extensions to attribute
* types in DNs ...
*/
}
/*
- * should we rather trim ';' from
- * attribute types?
+ * we trim ';' and following lang
+ * and so from attribute types
*/
endPos = p;
for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
break;
}
- /* FIXME: here STRING means UTF-8 string, right? */
+ /*
+ * here STRING means RFC 2253 string
+ * FIXME: what about DCE strings?
+ */
state = B4STRINGVALUE;
break;
int rdnsep = 0;
/*
- * FIXME: should we accept empty values?
+ * we accept empty values
*/
-
ava = ldapava_new( attrType, attrValue,
attrValueEncoding );
if ( ava == NULL ) {
}
newRDN = rdn;
- /* add the AVA to this RDN */
-#if 1
-#if 0
- {
- wchar_t buf[1024];
-
- ldap_x_utf8s_to_wcs( buf, attrType,
- sizeof( buf ) );
- fprintf( stderr, "***< %ls", buf );
- ldap_x_utf8s_to_wcs( buf, attrValue->bv_val,
- sizeof( buf ) );
- fprintf( stderr, " = %ls >***\n", buf );
- }
-#else
- fprintf( stderr, "***< %s = %s >***\n",
- attrType, attrValue->bv_val );
-#endif
-#endif
-
/*
* if we got an AVA separator ('+', | ',' * for DCE )
* we expect a new AVA for this RDN; otherwise
* we add the RDN to the DN
*/
-
switch ( LDAP_DN_FORMAT( flags ) ) {
case LDAP_DN_FORMAT_LDAPV3:
case LDAP_DN_FORMAT_LDAPV2:
str2strval( const char *str, struct berval **val, const char **next, unsigned flags, unsigned *retFlags )
{
const char *p, *startPos, *endPos = NULL;
- ber_len_t len, escapes;
+ ber_len_t len, escapes, unescapes;
assert( str );
assert( val );
*val = NULL;
*next = NULL;
-
- for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
+
+ for ( startPos = p = str, escapes = 0, unescapes = 0; p[ 0 ]; p++ ) {
if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
p++;
if ( p[ 0 ] == '\0' ) {
}
if ( LDAP_DN_HEXPAIR( p ) ) {
+ char c;
+#ifdef PARSE_UTF8
+ int cl;
+
/*
- * FIXME: here I guess I need to decode
- * the byte; it would be nice to check
+ * here I guess I need to decode
+ * the byte; let's also check
* the resulting encoding is a legal
* UTF-8 char
*/
- p++;
+
+#endif /* PARSE_UTF8 */
+ hexstr2bin( p, &c );
+#ifdef PARSE_UTF8
+ cl = ldap_utf8_charlen( &c );
+
+ for ( escapes += 2; --cl; escapes += 2 ) {
+ p += 2;
+
+ /*
+ * there must be another escaped
+ * hexpair ...
+ */
+ if ( !LDAP_DN_ESCAPE( p[ 0 ] ) ) {
+ return( 1 );
+ }
+ p++;
+ if ( !LDAP_DN_HEXPAIR( p ) ) {
+ return( 1 );
+ }
+
+ /*
+ * that must be 10xxxxxx
+ */
+ hexstr2bin( p, &c );
+ if ( ( c & 0xc0 ) != 0x80 ) {
+ return( 1 );
+ }
+ }
+#else /* !PARSE_UTF8 */
escapes += 2;
+#endif /* !PARSE_UTF8 */
+
+ if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
+
+ /*
+ * we assume the string is UTF-8
+ */
+ *retFlags = LDAP_AVA_PRINTABLE;
+ }
+ p++;
- /*
- * we assume the string is UTF-8
- */
- *retFlags = LDAP_AVA_PRINTABLE;
continue;
}
* single hexdigit; maybe we
* shouldn't).
*/
+ unescapes++;
} else if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
break;
} else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
/*
* FIXME: maybe we can add
- * escapes?
+ * escapes if not pedantic?
*/
return( 1 );
}
/* strip trailing (unescaped) spaces */
for ( endPos = p - 1;
endPos > startPos + 1 &&
- LDAP_DN_ASCII_SPACE( endPos[ 0 ] ) &&
- !LDAP_DN_ESCAPE( endPos[ -1 ] );
+ LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
+ !LDAP_DN_ESCAPE( endPos[ -2 ] );
endPos-- ) {
/* no op */
}
/*
* FIXME: test memory?
*/
- len = ( endPos ? endPos : p ) - startPos - escapes;
+ len = ( endPos ? endPos : p ) - startPos - escapes - unescapes;
*val = LDAP_MALLOC( sizeof( struct berval ) );
( *val )->bv_len = len;
- if ( escapes == 0 ) {
+ if ( escapes == 0 && unescapes == 0 ) {
( *val )->bv_val = LDAP_STRNDUP( startPos, len );
} else {
ber_len_t s, d;
- char *utfStart = NULL;
( *val )->bv_val = LDAP_MALLOC( len + 1 );
for ( s = 0, d = 0; d < len; ) {
( *val )->bv_val[ d++ ] =
startPos[ s++ ];
} else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
- unsigned c;
+ char c;
hexstr2bin( &startPos[ s ], &c );
( *val )->bv_val[ d++ ] = c;
( *val )->bv_val[ d++ ] = startPos[ s++ ];
}
}
+
( *val )->bv_val[ d ] = '\0';
assert( strlen( ( *val )->bv_val ) == len );
}
*next = NULL;
for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
- /*
- * FIXME: is '\' the escape char for DCE?
- */
if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
p++;
if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
} else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
break;
}
+
+ /*
+ * FIXME: can we accept anything else? I guess we need
+ * to stop if a value is not legal
+ */
}
/*
/* strip trailing (unescaped) spaces */
for ( endPos = p - 1;
endPos > startPos + 1 &&
- LDAP_DN_ASCII_SPACE( endPos[ 0 ] ) &&
- !LDAP_DN_ESCAPE( endPos[ -1 ] );
+ LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
+ !LDAP_DN_ESCAPE( endPos[ -2 ] );
endPos-- ) {
/* no op */
}
*next = NULL;
/*
- * FIXME: need to check how escape stuff works
- * with LDAPv2 (RFC 1779, right?)
+ * LDAPv2 (RFC 1779)
*/
for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
} else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
break;
}
+
+ /*
+ * FIXME: can we accept anything else? I guess we need
+ * to stop if a value is not legal
+ */
}
/* strip trailing (unescaped) spaces */
*val = NULL;
*next = NULL;
- /*
- * FIXME: of course, as long as we remove the quotes,
- * we need to escape chars as required ...
- */
-
/* initial quote already eaten */
for ( startPos = p = str; p[ 0 ]; p++ ) {
/*
- * FIXME: According to RFC 1779, the quoted value can
+ * According to RFC 1779, the quoted value can
* contain escaped as well as unescaped special values;
* as a consequence we tolerate escaped values
* (e.g. '"\,"' -> '\,') and escape unescaped specials
p++;
break;
}
+
+ /*
+ * FIXME: can we accept anything else? I guess we need
+ * to stop if a value is not legal
+ */
}
if ( endPos == NULL ) {
return( 1 );
}
- /* FIXME: strip trailing (unescaped) spaces? */
+ /* Strip trailing (unescaped) spaces */
for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
/* no op */
}
}
static int
-hexstr2bin( const char *str, unsigned *c )
+hexstr2bin( const char *str, char *c )
{
- unsigned c1, c2;
+ char c1, c2;
assert( str );
assert( c );
*next = NULL;
for ( startPos = p = str; p[ 0 ]; p += 2 ) {
- if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
+ switch ( LDAP_DN_FORMAT( flags ) ) {
+ case LDAP_DN_FORMAT_LDAPV3:
+ case LDAP_DN_FORMAT_LDAPV2:
+ if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
+ goto end_of_value;
+ }
+ break;
+
+ case LDAP_DN_FORMAT_DCE:
+ if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
+ goto end_of_value;
+ }
break;
}
endPos = p;
for ( ; p[ 0 ]; p++ ) {
- if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
+ switch ( LDAP_DN_FORMAT( flags ) ) {
+ case LDAP_DN_FORMAT_LDAPV3:
+ case LDAP_DN_FORMAT_LDAPV2:
+ if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
+ goto end_of_value;
+ }
+ break;
+
+ case LDAP_DN_FORMAT_DCE:
+ if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
+ goto end_of_value;
+ }
break;
}
}
}
}
+end_of_value:;
+
len = ( ( endPos ? endPos : p ) - startPos ) / 2;
/* must be even! */
assert( 2 * len == ( endPos ? endPos : p ) - startPos );
}
for ( s = 0, d = 0; d < len; s += 2, d++ ) {
- unsigned c;
+ char c;
hexstr2bin( &startPos[ s ], &c );
assert( val );
assert( str );
- /* FIXME: what should I do with a null value? */
if ( val->bv_len == 0 ) {
return( 0 );
}
static ber_len_t
strval2strlen( struct berval *val, unsigned flags )
{
- ber_len_t l, cl;
+ ber_len_t l, cl = 1;
char *p;
-
+
assert( val );
- /* FIXME: what should I do with a null value? */
if ( val->bv_len == 0 ) {
return( 0 );
}
for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
+#ifdef PARSE_UTF8
cl = ldap_utf8_charlen( p );
if ( cl > 1 ) {
/* need to escape it */
l += 3 * cl;
+#else /* !PARSE_UTF8 */
+ if ( ( p[ 0 ] & 0x80 ) != 0x00 ) {
+ /* need to escape it */
+ l += 3;
+#endif /* !PARSE_UTF8 */
} else if ( ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
|| ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
|| LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
static int
strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
{
- ber_len_t s, d, cl, end;
+ ber_len_t s, d, end;
assert( val );
assert( str );
assert( len );
- /* FIXME: what should I do with a null value? */
if ( val->bv_len == 0 ) {
*len = 0;
return( 0 );
* of the value
*/
for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
- cl = ldap_utf8_charlen( &val->bv_val[ s ] );
+#ifdef PARSE_UTF8
+ ber_len_t cl = ldap_utf8_charlen( &val->bv_val[ s ] );
if ( cl > 1 ) {
for ( ; cl--; ) {
+#else /* !PARSE_UTF8 */
+ if ( ( val->bv_val[ s ] & 0x80 ) != 0x00 ) {
+#endif /* !PARSE_UTF8 */
str[ d++ ] = '\\';
byte2hexpair( &val->bv_val[ s ], &str[ d ] );
s++;
d += 2;
+#ifdef PARSE_UTF8
}
+#endif /* !PARSE_UTF8 */
} else {
if ( ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
|| ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
assert( val );
- /* FIXME: what should I do with a null value? */
if ( val->bv_len == 0 ) {
return( 0 );
}
if ( flags & LDAP_AVA_PRINTABLE ) {
/*
- * FIXME: binary encoded BER
+ * Turn value into a binary encoded BER
*/
return( 0 );
}
}
- return l;
+ return( l );
}
/*
assert( str );
assert( len );
- /* FIXME: what should I do with a null value? */
if ( val->bv_len == 0 ) {
*len = 0;
- return ( 0 );
+ return( 0 );
}
if ( flags & LDAP_AVA_PRINTABLE ) {
/*
- * FIXME: binary encoded BER
+ * Turn value into a binary encoded BER
*/
+ *len = 0;
return( -1 );
} else {
assert( val );
- /* FIXME: what should I do with a null value? */
if ( val->bv_len == 0 ) {
- return ( 0 );
+ return( 0 );
}
if ( flags & LDAP_AVA_PRINTABLE ) {
/*
- * FIXME: binary encoded BER
+ * FIXME: Turn the value into a binary encoded BER?
*/
return( 0 );
}
}
- return l;
+ return( l );
}
/*
assert( str );
assert( len );
- /* FIXME: what should I do with a null value? */
if ( val->bv_len == 0 ) {
*len = 0;
- return ( 0 );
+ return( 0 );
}
if ( flags & LDAP_AVA_PRINTABLE ) {
/*
- * FIXME: binary encoded BER
+ * FIXME: Turn the value into a binary encoded BER?
*/
+ *len = 0;
return( -1 );
} else {
assert( val );
- /* FIXME: what should I do with a null value? */
if ( val->bv_len == 0 ) {
- return ( 0 );
+ return( 0 );
}
if ( flags & LDAP_AVA_PRINTABLE ) {
/*
- * FIXME: binary encoded BER
+ * FIXME: Turn the value into a binary encoded BER?
*/
return( 0 );
}
}
- return l;
+ return( l );
}
/*
assert( str );
assert( len );
- /* FIXME: what should I do with a null value? */
if ( val->bv_len == 0 ) {
*len = 0;
- return ( 0 );
+ return( 0 );
}
if ( flags & LDAP_AVA_PRINTABLE ) {
/*
- * FIXME: binary encoded BER
+ * FIXME: Turn the value into a binary encoded BER?
*/
+ *len = 0;
return( -1 );
} else {
assert( rdn[ 0 ][ 0 ] );
ava = rdn[ 0 ][ 0 ];
- /* FIXME: no composite rdn or non-"dc" types */
- /* FIXME: we do not allow binary values in domain */
+ /* FIXME: no composite rdn or non-"dc" types, right? */
+ /* FIXME: we do not allow binary values in domain, right? */
if ( rdn[ 1 ] || strcasecmp( ava->la_attr, LDAP_DC_ATTR )
- || ava->la_flags & LDAP_AVA_BINARY ) {
+ || ava->la_flags != LDAP_AVA_STRING ) {
break;
}
return( domain );
}
+static ber_len_t
+rdn2strlen( LDAPRDN *rdn )
+{
+ int iAVA;
+ ber_len_t len = 0;
+
+ for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
+ LDAPAVA *ava = rdn[ iAVA ][ 0 ];
+
+ /* len(type) + '=' + '+' | ',' */
+ len += strlen( ava->la_attr ) + 2;
+
+ if ( ava->la_flags & LDAP_AVA_BINARY ) {
+ /* octothorpe + twice the length */
+ len += 1 + 2 * ava->la_value->bv_len;
+ } else {
+ len += strval2strlen( ava->la_value, ava->la_flags );
+ }
+ }
+
+ return( len );
+}
+
+static int
+rdn2str( LDAPRDN *rdn, char *str, ber_len_t *len )
+{
+ int iAVA;
+ ber_len_t l = 0;
+
+ for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
+ LDAPAVA *ava = rdn[ iAVA ][ 0 ];
+ ber_len_t al = strlen( ava->la_attr );
+
+ AC_MEMCPY( &str[ l ], ava->la_attr, al );
+ l += al;
+
+ str[ l++ ] = '=';
+
+ if ( ava->la_flags & LDAP_AVA_BINARY ) {
+ str[ l++ ] = '#';
+ binval2hexstr( ava->la_value, &str[ l ] );
+ l += 2 * ava->la_value->bv_len;
+ } else {
+ ber_len_t vl;
+ strval2str( ava->la_value, &str[ l ],
+ ava->la_flags, &vl );
+ l += vl;
+ }
+ str[ l++ ] = ( rdn[ iAVA + 1 ] ? '+' : ',' );
+ }
+
+ *len = l;
+
+ return( 0 );
+}
+
+static ber_len_t
+rdn2UFNstrlen( LDAPRDN *rdn )
+{
+ int iAVA;
+ ber_len_t len = 0;
+
+ for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
+ LDAPAVA *ava = rdn[ iAVA ][ 0 ];
+
+ /* ' + ' | ', ' */
+ len += ( rdn[ iAVA + 1 ] ? 3 : 2 );
+
+ /* FIXME: are binary values allowed in UFN? */
+ if ( ava->la_flags & LDAP_AVA_BINARY ) {
+ /* octothorpe + twice the value */
+ len += 1 + 2 * ava->la_value->bv_len;
+ } else {
+ len += strval2strlen( ava->la_value, ava->la_flags );
+ }
+ }
+
+ return( len );
+}
+
+static int
+rdn2UFNstr( LDAPRDN *rdn, char *str, ber_len_t *len )
+{
+ int iAVA;
+ ber_len_t l = 0;
+
+ for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
+ LDAPAVA *ava = rdn[ iAVA ][ 0 ];
+
+ if ( ava->la_flags & LDAP_AVA_BINARY ) {
+ str[ l++ ] = '#';
+ binval2hexstr( ava->la_value, &str[ l ] );
+ l += 2 * ava->la_value->bv_len;
+ } else {
+ ber_len_t vl;
+ strval2str( ava->la_value, &str[ l ],
+ ava->la_flags, &vl );
+ l += vl;
+ }
+
+ if ( rdn[ iAVA + 1 ]) {
+ AC_MEMCPY( &str[ l ], " + ", 3 );
+ l += 3;
+ } else {
+ AC_MEMCPY( &str[ l ], ", ", 2 );
+ l += 2;
+ }
+ }
+
+ *len = l;
+
+ return( 0 );
+}
+
+int
+ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
+{
+ int rc, back;
+ ber_len_t l;
+
+ assert( str );
+
+ if ( rdn == NULL ) {
+ *str = LDAP_STRDUP( "" );
+ return( LDAP_SUCCESS );
+ }
+
+ switch ( LDAP_DN_FORMAT( flags ) ) {
+ case LDAP_DN_FORMAT_LDAPV3:
+ l = rdn2strlen( rdn );
+ break;
+
+ case LDAP_DN_FORMAT_UFN:
+ l = rdn2UFNstrlen( rdn );
+ break;
+
+ default:
+ return( LDAP_OTHER );
+ }
+
+ *str = LDAP_MALLOC( l + 1 );
+
+ switch ( LDAP_DN_FORMAT( flags ) ) {
+ case LDAP_DN_FORMAT_LDAPV3:
+ rc = rdn2str( rdn, *str, &l );
+ back = 1;
+ break;
+
+ case LDAP_DN_FORMAT_UFN:
+ rc = rdn2UFNstr( rdn, *str, &l );
+ back = 2;
+ break;
+ }
+
+ if ( rc ) {
+ ldap_memfree( *str );
+ return( LDAP_OTHER );
+ }
+
+ ( *str )[ l - back ] = '\0';
+
+ return( LDAP_SUCCESS );
+}
+
/*
* Very bulk implementation; many optimizations can be performed
* - a NULL dn results in an empty string ""
* b) does DCE/AD support UTF-8?
* no clue; don't think so.
* c) what do we do when binary values must be converted in UTF/DCE/AD?
- * use binary encode
+ * use binary encoded BER
*/
int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
{
case LDAP_DN_FORMAT_LDAPV3:
s2l = strval2strlen;
s2s = strval2str;
- goto v2_v3;
+ /*
+ * LDAPv3 uses helpers
+ */
+ for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
+ len += rdn2strlen( dn[ iRDN ][ 0 ] );
+ }
+
+ if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
+ rc = LDAP_NO_MEMORY;
+ break;
+ }
+
+ for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
+ ber_len_t vl;
+ rdn2str( dn[ iRDN ][ 0 ], &( *str )[ l ], &vl );
+ l += vl;
+ }
+
+ assert( l == len );
+
+ /*
+ * trim the last ',' (the allocated memory
+ * is one byte longer than required)
+ */
+ ( *str )[ len - 1 ] = '\0';
+
+ rc = LDAP_SUCCESS;
+ break;
+
case LDAP_DN_FORMAT_LDAPV2:
s2l = strval2IA5strlen;
s2s = strval2IA5str;
-v2_v3:
/*
- * FIXME: we're treating LDAPv3 and LDAPv2 the same way;
- * is it correct? No. LDAPv2 need to use binary encode
- * ( '#' + hex form of BER) in case of non-IA5 chars.
+ * LDAPv2 follows the regular path
*/
for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
LDAPRDN *rdn = dn[ iRDN ][ 0 ];
/* len(type) + '=' + '+' | ',' */
len += strlen( ava->la_attr ) + 2;
- /* FIXME: are binary values allowed
- * in LDAPv2? */
if ( ava->la_flags & LDAP_AVA_BINARY ) {
/* octothorpe + twice the length */
len += 1 + 2 * ava->la_value->bv_len;
*/
for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
- LDAPRDN *rdn = dn[ iRDN ][ 0 ];
-
- for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
- LDAPAVA *ava = rdn[ iAVA ][ 0 ];
-
- /* ' + ' | ', ' */
- len += ( rdn[ iAVA + 1 ] ? 3 : 2 );
-
- /* FIXME: are binary values allowed in UFN? */
- if ( ava->la_flags & LDAP_AVA_BINARY ) {
- /* octothorpe + twice the value */
- len += 1 + 2 * ava->la_value->bv_len;
- } else {
- len += strval2strlen( ava->la_value,
- ava->la_flags );
- }
- }
+ len += rdn2UFNstrlen( dn[ iRDN ][ 0 ] );
}
if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
}
for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
- LDAPRDN *rdn = dn[ iRDN ][ 0 ];
-
- for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
- LDAPAVA *ava = rdn[ iAVA ][ 0 ];
-
- if ( ava->la_flags & LDAP_AVA_BINARY ) {
- ( *str )[ l++ ] = '#';
- binval2hexstr( ava->la_value,
- &( *str )[ l ] );
- l += 2 * ava->la_value->bv_len;
- } else {
- ber_len_t vl;
- strval2str( ava->la_value,
- &( *str )[ l ],
- ava->la_flags, &vl );
- l += vl;
- }
-
- if ( rdn[ iAVA + 1 ]) {
- AC_MEMCPY( &( *str )[ l ], " + ", 3 );
- l += 3;
- } else {
- AC_MEMCPY( &( *str )[ l ], ", ", 2 );
- l += 2;
- }
- }
+ ber_len_t vl;
+ rdn2UFNstr( dn[ iRDN ][ 0 ], &( *str )[ l ], &vl );
+ l += vl;
}
/*
LDAPRDN *rdn = dn[ iRDN ][ 0 ];
/*
- * FIXME: does DCE allow '+'?
+ * DCE uses ',' for composite RDNs
*/
for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
LDAPAVA *ava = rdn[ iAVA ][ 0 ];
int first = 1;
/*
- * FIXME: strictly speaking, AD canonical requires
- * a DN to be in the form "..., dc=smtg"
+ * Strictly speaking, AD canonical requires
+ * a DN to be in the form "..., dc=smtg",
+ * i.e. terminated by a domain component
*/
if ( flags & LDAP_DN_PEDANTIC ) {
LDAP_FREE( *str );
return( rc );
}
-