1*549b59edSchristos /* $NetBSD: getdn.c,v 1.3 2021/08/14 16:14:56 christos Exp $ */
24e6df137Slukem
3d11b170bStron /* $OpenLDAP$ */
42de962bdSlukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
52de962bdSlukem *
6*549b59edSchristos * Copyright 1998-2021 The OpenLDAP Foundation.
72de962bdSlukem * All rights reserved.
82de962bdSlukem *
92de962bdSlukem * Redistribution and use in source and binary forms, with or without
102de962bdSlukem * modification, are permitted only as authorized by the OpenLDAP
112de962bdSlukem * Public License.
122de962bdSlukem *
132de962bdSlukem * A copy of this license is available in the file LICENSE in the
142de962bdSlukem * top-level directory of the distribution or, alternatively, at
152de962bdSlukem * <http://www.OpenLDAP.org/license.html>.
162de962bdSlukem */
172de962bdSlukem /* Portions Copyright (c) 1994 Regents of the University of Michigan.
182de962bdSlukem * All rights reserved.
192de962bdSlukem */
202de962bdSlukem
21376af7d7Schristos #include <sys/cdefs.h>
22*549b59edSchristos __RCSID("$NetBSD: getdn.c,v 1.3 2021/08/14 16:14:56 christos Exp $");
23376af7d7Schristos
242de962bdSlukem #include "portable.h"
252de962bdSlukem
262de962bdSlukem #include <stdio.h>
272de962bdSlukem
282de962bdSlukem #include <ac/stdlib.h>
292de962bdSlukem #include <ac/socket.h>
302de962bdSlukem #include <ac/string.h>
312de962bdSlukem #include <ac/time.h>
322de962bdSlukem
332de962bdSlukem #include "ldap-int.h"
342de962bdSlukem #include "ldap_schema.h"
354e27b3e8Schristos #include "ldif.h"
362de962bdSlukem
372de962bdSlukem /* extension to UFN that turns trailing "dc=value" rdns in DNS style,
382de962bdSlukem * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */
392de962bdSlukem #define DC_IN_UFN
402de962bdSlukem
412de962bdSlukem /* parsing/printing routines */
422de962bdSlukem static int str2strval( const char *str, ber_len_t stoplen, struct berval *val,
432de962bdSlukem const char **next, unsigned flags, int *retFlags, void *ctx );
442de962bdSlukem static int DCE2strval( const char *str, struct berval *val,
452de962bdSlukem const char **next, unsigned flags, void *ctx );
462de962bdSlukem static int IA52strval( const char *str, struct berval *val,
472de962bdSlukem const char **next, unsigned flags, void *ctx );
482de962bdSlukem static int quotedIA52strval( const char *str, struct berval *val,
492de962bdSlukem const char **next, unsigned flags, void *ctx );
502de962bdSlukem static int hexstr2binval( const char *str, struct berval *val,
512de962bdSlukem const char **next, unsigned flags, void *ctx );
522de962bdSlukem static int hexstr2bin( const char *str, char *c );
532de962bdSlukem static int byte2hexpair( const char *val, char *pair );
542de962bdSlukem static int binval2hexstr( struct berval *val, char *str );
552de962bdSlukem static int strval2strlen( struct berval *val, unsigned flags,
562de962bdSlukem ber_len_t *len );
572de962bdSlukem static int strval2str( struct berval *val, char *str, unsigned flags,
582de962bdSlukem ber_len_t *len );
592de962bdSlukem static int strval2IA5strlen( struct berval *val, unsigned flags,
602de962bdSlukem ber_len_t *len );
612de962bdSlukem static int strval2IA5str( struct berval *val, char *str, unsigned flags,
622de962bdSlukem ber_len_t *len );
632de962bdSlukem static int strval2DCEstrlen( struct berval *val, unsigned flags,
642de962bdSlukem ber_len_t *len );
652de962bdSlukem static int strval2DCEstr( struct berval *val, char *str, unsigned flags,
662de962bdSlukem ber_len_t *len );
672de962bdSlukem static int strval2ADstrlen( struct berval *val, unsigned flags,
682de962bdSlukem ber_len_t *len );
692de962bdSlukem static int strval2ADstr( struct berval *val, char *str, unsigned flags,
702de962bdSlukem ber_len_t *len );
712de962bdSlukem static int dn2domain( LDAPDN dn, struct berval *bv, int pos, int *iRDN );
722de962bdSlukem
732de962bdSlukem /* AVA helpers */
742de962bdSlukem static LDAPAVA * ldapava_new(
752de962bdSlukem const struct berval *attr, const struct berval *val, unsigned flags, void *ctx );
762de962bdSlukem
772de962bdSlukem /* Higher level helpers */
782de962bdSlukem static int rdn2strlen( LDAPRDN rdn, unsigned flags, ber_len_t *len,
792de962bdSlukem int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
802de962bdSlukem static int rdn2str( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len,
812de962bdSlukem int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
822de962bdSlukem static int rdn2UFNstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len );
832de962bdSlukem static int rdn2UFNstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len );
842de962bdSlukem static int rdn2DCEstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len );
852de962bdSlukem static int rdn2DCEstr( LDAPRDN rdn, char *str, unsigned flag, ber_len_t *len, int first );
862de962bdSlukem static int rdn2ADstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len );
872de962bdSlukem static int rdn2ADstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first );
882de962bdSlukem
892de962bdSlukem /*
902de962bdSlukem * RFC 1823 ldap_get_dn
912de962bdSlukem */
922de962bdSlukem char *
ldap_get_dn(LDAP * ld,LDAPMessage * entry)932de962bdSlukem ldap_get_dn( LDAP *ld, LDAPMessage *entry )
942de962bdSlukem {
952de962bdSlukem char *dn;
962de962bdSlukem BerElement tmp;
972de962bdSlukem
98*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, "ldap_get_dn\n" );
992de962bdSlukem
1002de962bdSlukem assert( ld != NULL );
1012de962bdSlukem assert( LDAP_VALID(ld) );
1022de962bdSlukem assert( entry != NULL );
1032de962bdSlukem
1042de962bdSlukem tmp = *entry->lm_ber; /* struct copy */
1052de962bdSlukem if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
1062de962bdSlukem ld->ld_errno = LDAP_DECODING_ERROR;
1072de962bdSlukem return( NULL );
1082de962bdSlukem }
1092de962bdSlukem
1102de962bdSlukem return( dn );
1112de962bdSlukem }
1122de962bdSlukem
1132de962bdSlukem int
ldap_get_dn_ber(LDAP * ld,LDAPMessage * entry,BerElement ** berout,BerValue * dn)1142de962bdSlukem ldap_get_dn_ber( LDAP *ld, LDAPMessage *entry, BerElement **berout,
1152de962bdSlukem BerValue *dn )
1162de962bdSlukem {
1172de962bdSlukem BerElement tmp, *ber;
1182de962bdSlukem ber_len_t len = 0;
1192de962bdSlukem int rc = LDAP_SUCCESS;
1202de962bdSlukem
121*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, "ldap_get_dn_ber\n" );
1222de962bdSlukem
1232de962bdSlukem assert( ld != NULL );
1242de962bdSlukem assert( LDAP_VALID(ld) );
1252de962bdSlukem assert( entry != NULL );
1262de962bdSlukem assert( dn != NULL );
1272de962bdSlukem
1282de962bdSlukem dn->bv_val = NULL;
1292de962bdSlukem dn->bv_len = 0;
1302de962bdSlukem
1312de962bdSlukem if ( berout ) {
1322de962bdSlukem *berout = NULL;
1332de962bdSlukem ber = ldap_alloc_ber_with_options( ld );
1342de962bdSlukem if( ber == NULL ) {
1352de962bdSlukem return LDAP_NO_MEMORY;
1362de962bdSlukem }
1372de962bdSlukem *berout = ber;
1382de962bdSlukem } else {
1392de962bdSlukem ber = &tmp;
1402de962bdSlukem }
1412de962bdSlukem
1422de962bdSlukem *ber = *entry->lm_ber; /* struct copy */
1432de962bdSlukem if ( ber_scanf( ber, "{ml{" /*}*/, dn, &len ) == LBER_ERROR ) {
1442de962bdSlukem rc = ld->ld_errno = LDAP_DECODING_ERROR;
1452de962bdSlukem }
1462de962bdSlukem if ( rc == LDAP_SUCCESS ) {
1472de962bdSlukem /* set the length to avoid overrun */
1482de962bdSlukem rc = ber_set_option( ber, LBER_OPT_REMAINING_BYTES, &len );
1492de962bdSlukem if( rc != LBER_OPT_SUCCESS ) {
1502de962bdSlukem rc = ld->ld_errno = LDAP_LOCAL_ERROR;
1512de962bdSlukem }
1522de962bdSlukem }
1532de962bdSlukem if ( rc != LDAP_SUCCESS && berout ) {
1542de962bdSlukem ber_free( ber, 0 );
1552de962bdSlukem *berout = NULL;
1562de962bdSlukem }
1572de962bdSlukem return rc;
1582de962bdSlukem }
1592de962bdSlukem
1602de962bdSlukem /*
1612de962bdSlukem * RFC 1823 ldap_dn2ufn
1622de962bdSlukem */
1632de962bdSlukem char *
ldap_dn2ufn(LDAP_CONST char * dn)1642de962bdSlukem ldap_dn2ufn( LDAP_CONST char *dn )
1652de962bdSlukem {
1662de962bdSlukem char *out = NULL;
1672de962bdSlukem
168*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n" );
1692de962bdSlukem
1702de962bdSlukem ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP,
1712de962bdSlukem &out, LDAP_DN_FORMAT_UFN );
1722de962bdSlukem
1732de962bdSlukem return( out );
1742de962bdSlukem }
1752de962bdSlukem
1762de962bdSlukem /*
1772de962bdSlukem * RFC 1823 ldap_explode_dn
1782de962bdSlukem */
1792de962bdSlukem char **
ldap_explode_dn(LDAP_CONST char * dn,int notypes)1802de962bdSlukem ldap_explode_dn( LDAP_CONST char *dn, int notypes )
1812de962bdSlukem {
1822de962bdSlukem LDAPDN tmpDN;
1832de962bdSlukem char **values = NULL;
1842de962bdSlukem int iRDN;
1852de962bdSlukem unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
1862de962bdSlukem
187*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, "ldap_explode_dn\n" );
1882de962bdSlukem
1892de962bdSlukem if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP )
1902de962bdSlukem != LDAP_SUCCESS ) {
1912de962bdSlukem return NULL;
1922de962bdSlukem }
1932de962bdSlukem
1942de962bdSlukem if( tmpDN == NULL ) {
1952de962bdSlukem values = LDAP_MALLOC( sizeof( char * ) );
1962de962bdSlukem if( values == NULL ) return NULL;
1972de962bdSlukem
1982de962bdSlukem values[0] = NULL;
1992de962bdSlukem return values;
2002de962bdSlukem }
2012de962bdSlukem
2022de962bdSlukem for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ );
2032de962bdSlukem
2042de962bdSlukem values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iRDN ) );
2052de962bdSlukem if ( values == NULL ) {
2062de962bdSlukem ldap_dnfree( tmpDN );
2072de962bdSlukem return NULL;
2082de962bdSlukem }
2092de962bdSlukem
2102de962bdSlukem for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) {
2112de962bdSlukem ldap_rdn2str( tmpDN[ iRDN ], &values[ iRDN ], flag );
2122de962bdSlukem }
2132de962bdSlukem ldap_dnfree( tmpDN );
2142de962bdSlukem values[ iRDN ] = NULL;
2152de962bdSlukem
2162de962bdSlukem return values;
2172de962bdSlukem }
2182de962bdSlukem
2192de962bdSlukem char **
ldap_explode_rdn(LDAP_CONST char * rdn,int notypes)2202de962bdSlukem ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
2212de962bdSlukem {
2222de962bdSlukem LDAPRDN tmpRDN;
2232de962bdSlukem char **values = NULL;
2242de962bdSlukem const char *p;
2252de962bdSlukem int iAVA;
2262de962bdSlukem
227*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n" );
2282de962bdSlukem
2292de962bdSlukem /*
2302de962bdSlukem * we only parse the first rdn
2312de962bdSlukem * FIXME: we prefer efficiency over checking if the _ENTIRE_
2322de962bdSlukem * dn can be parsed
2332de962bdSlukem */
2342de962bdSlukem if ( ldap_str2rdn( rdn, &tmpRDN, (char **) &p, LDAP_DN_FORMAT_LDAP )
2352de962bdSlukem != LDAP_SUCCESS ) {
2362de962bdSlukem return( NULL );
2372de962bdSlukem }
2382de962bdSlukem
2392de962bdSlukem for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) ;
2402de962bdSlukem values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iAVA ) );
2412de962bdSlukem if ( values == NULL ) {
2422de962bdSlukem ldap_rdnfree( tmpRDN );
2432de962bdSlukem return( NULL );
2442de962bdSlukem }
2452de962bdSlukem
2462de962bdSlukem for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) {
2472de962bdSlukem ber_len_t l = 0, vl, al = 0;
2482de962bdSlukem char *str;
2492de962bdSlukem LDAPAVA *ava = tmpRDN[ iAVA ];
2502de962bdSlukem
2512de962bdSlukem if ( ava->la_flags & LDAP_AVA_BINARY ) {
2522de962bdSlukem vl = 1 + 2 * ava->la_value.bv_len;
2532de962bdSlukem
2542de962bdSlukem } else {
2552de962bdSlukem if ( strval2strlen( &ava->la_value,
2562de962bdSlukem ava->la_flags, &vl ) ) {
2572de962bdSlukem goto error_return;
2582de962bdSlukem }
2592de962bdSlukem }
2602de962bdSlukem
2612de962bdSlukem if ( !notypes ) {
2622de962bdSlukem al = ava->la_attr.bv_len;
2632de962bdSlukem l = vl + ava->la_attr.bv_len + 1;
2642de962bdSlukem
2652de962bdSlukem str = LDAP_MALLOC( l + 1 );
266*549b59edSchristos if ( str == NULL ) {
267*549b59edSchristos goto error_return;
268*549b59edSchristos }
2692de962bdSlukem AC_MEMCPY( str, ava->la_attr.bv_val,
2702de962bdSlukem ava->la_attr.bv_len );
2712de962bdSlukem str[ al++ ] = '=';
2722de962bdSlukem
2732de962bdSlukem } else {
2742de962bdSlukem l = vl;
2752de962bdSlukem str = LDAP_MALLOC( l + 1 );
276*549b59edSchristos if ( str == NULL ) {
277*549b59edSchristos goto error_return;
278*549b59edSchristos }
2792de962bdSlukem }
2802de962bdSlukem
2812de962bdSlukem if ( ava->la_flags & LDAP_AVA_BINARY ) {
2822de962bdSlukem str[ al++ ] = '#';
2832de962bdSlukem if ( binval2hexstr( &ava->la_value, &str[ al ] ) ) {
2842de962bdSlukem goto error_return;
2852de962bdSlukem }
2862de962bdSlukem
2872de962bdSlukem } else {
2882de962bdSlukem if ( strval2str( &ava->la_value, &str[ al ],
2892de962bdSlukem ava->la_flags, &vl ) ) {
2902de962bdSlukem goto error_return;
2912de962bdSlukem }
2922de962bdSlukem }
2932de962bdSlukem
2942de962bdSlukem str[ l ] = '\0';
2952de962bdSlukem values[ iAVA ] = str;
2962de962bdSlukem }
2972de962bdSlukem values[ iAVA ] = NULL;
2982de962bdSlukem
2992de962bdSlukem ldap_rdnfree( tmpRDN );
3002de962bdSlukem
3012de962bdSlukem return( values );
3022de962bdSlukem
3032de962bdSlukem error_return:;
3042de962bdSlukem LBER_VFREE( values );
3052de962bdSlukem ldap_rdnfree( tmpRDN );
3062de962bdSlukem return( NULL );
3072de962bdSlukem }
3082de962bdSlukem
3092de962bdSlukem char *
ldap_dn2dcedn(LDAP_CONST char * dn)3102de962bdSlukem ldap_dn2dcedn( LDAP_CONST char *dn )
3112de962bdSlukem {
3122de962bdSlukem char *out = NULL;
3132de962bdSlukem
314*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n" );
3152de962bdSlukem
3162de962bdSlukem ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP,
3172de962bdSlukem &out, LDAP_DN_FORMAT_DCE );
3182de962bdSlukem
3192de962bdSlukem return( out );
3202de962bdSlukem }
3212de962bdSlukem
3222de962bdSlukem char *
ldap_dcedn2dn(LDAP_CONST char * dce)3232de962bdSlukem ldap_dcedn2dn( LDAP_CONST char *dce )
3242de962bdSlukem {
3252de962bdSlukem char *out = NULL;
3262de962bdSlukem
327*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n" );
3282de962bdSlukem
3292de962bdSlukem ( void )ldap_dn_normalize( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
3302de962bdSlukem
3312de962bdSlukem return( out );
3322de962bdSlukem }
3332de962bdSlukem
3342de962bdSlukem char *
ldap_dn2ad_canonical(LDAP_CONST char * dn)3352de962bdSlukem ldap_dn2ad_canonical( LDAP_CONST char *dn )
3362de962bdSlukem {
3372de962bdSlukem char *out = NULL;
3382de962bdSlukem
339*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n" );
3402de962bdSlukem
3412de962bdSlukem ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP,
3422de962bdSlukem &out, LDAP_DN_FORMAT_AD_CANONICAL );
3432de962bdSlukem
3442de962bdSlukem return( out );
3452de962bdSlukem }
3462de962bdSlukem
3472de962bdSlukem /*
3482de962bdSlukem * function that changes the string representation of dnin
3492de962bdSlukem * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
3502de962bdSlukem *
3512de962bdSlukem * fin can be one of:
3522de962bdSlukem * LDAP_DN_FORMAT_LDAP (RFC 4514 liberal, plus some RFC 1779)
3532de962bdSlukem * LDAP_DN_FORMAT_LDAPV3 (RFC 4514)
3542de962bdSlukem * LDAP_DN_FORMAT_LDAPV2 (RFC 1779)
3552de962bdSlukem * LDAP_DN_FORMAT_DCE (?)
3562de962bdSlukem *
3572de962bdSlukem * fout can be any of the above except
3582de962bdSlukem * LDAP_DN_FORMAT_LDAP
3592de962bdSlukem * plus:
3602de962bdSlukem * LDAP_DN_FORMAT_UFN (RFC 1781, partial and with extensions)
3612de962bdSlukem * LDAP_DN_FORMAT_AD_CANONICAL (?)
3622de962bdSlukem */
3632de962bdSlukem int
ldap_dn_normalize(LDAP_CONST char * dnin,unsigned fin,char ** dnout,unsigned fout)3642de962bdSlukem ldap_dn_normalize( LDAP_CONST char *dnin,
3652de962bdSlukem unsigned fin, char **dnout, unsigned fout )
3662de962bdSlukem {
3672de962bdSlukem int rc;
3682de962bdSlukem LDAPDN tmpDN = NULL;
3692de962bdSlukem
370*549b59edSchristos Debug0( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n" );
3712de962bdSlukem
3722de962bdSlukem assert( dnout != NULL );
3732de962bdSlukem
3742de962bdSlukem *dnout = NULL;
3752de962bdSlukem
3762de962bdSlukem if ( dnin == NULL ) {
3772de962bdSlukem return( LDAP_SUCCESS );
3782de962bdSlukem }
3792de962bdSlukem
3802de962bdSlukem rc = ldap_str2dn( dnin , &tmpDN, fin );
3812de962bdSlukem if ( rc != LDAP_SUCCESS ) {
3822de962bdSlukem return( rc );
3832de962bdSlukem }
3842de962bdSlukem
3852de962bdSlukem rc = ldap_dn2str( tmpDN, dnout, fout );
3862de962bdSlukem
3872de962bdSlukem ldap_dnfree( tmpDN );
3882de962bdSlukem
3892de962bdSlukem return( rc );
3902de962bdSlukem }
3912de962bdSlukem
3922de962bdSlukem /* States */
3932de962bdSlukem #define B4AVA 0x0000
3942de962bdSlukem
3952de962bdSlukem /* #define B4ATTRTYPE 0x0001 */
3962de962bdSlukem #define B4OIDATTRTYPE 0x0002
3972de962bdSlukem #define B4STRINGATTRTYPE 0x0003
3982de962bdSlukem
3992de962bdSlukem #define B4AVAEQUALS 0x0100
4002de962bdSlukem #define B4AVASEP 0x0200
4012de962bdSlukem #define B4RDNSEP 0x0300
4022de962bdSlukem #define GOTAVA 0x0400
4032de962bdSlukem
4042de962bdSlukem #define B4ATTRVALUE 0x0010
4052de962bdSlukem #define B4STRINGVALUE 0x0020
4062de962bdSlukem #define B4IA5VALUEQUOTED 0x0030
4072de962bdSlukem #define B4IA5VALUE 0x0040
4082de962bdSlukem #define B4BINARYVALUE 0x0050
4092de962bdSlukem
4102de962bdSlukem /*
4112de962bdSlukem * Helpers (mostly from slap.h)
4122de962bdSlukem * c is assumed to Unicode in an ASCII compatible format (UTF-8)
4132de962bdSlukem * Macros assume "C" Locale (ASCII)
4142de962bdSlukem */
4152de962bdSlukem #define LDAP_DN_ASCII_SPACE(c) \
4162de962bdSlukem ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
4172de962bdSlukem #define LDAP_DN_ASCII_LOWER(c) LDAP_LOWER(c)
4182de962bdSlukem #define LDAP_DN_ASCII_UPPER(c) LDAP_UPPER(c)
4192de962bdSlukem #define LDAP_DN_ASCII_ALPHA(c) LDAP_ALPHA(c)
4202de962bdSlukem
4212de962bdSlukem #define LDAP_DN_ASCII_DIGIT(c) LDAP_DIGIT(c)
4222de962bdSlukem #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) LDAP_HEXLOWER(c)
4232de962bdSlukem #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) LDAP_HEXUPPER(c)
4242de962bdSlukem #define LDAP_DN_ASCII_HEXDIGIT(c) LDAP_HEX(c)
4252de962bdSlukem #define LDAP_DN_ASCII_ALNUM(c) LDAP_ALNUM(c)
4262de962bdSlukem #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' )
4272de962bdSlukem
4282de962bdSlukem /* attribute type */
4292de962bdSlukem #define LDAP_DN_OID_LEADCHAR(c) LDAP_DIGIT(c)
4302de962bdSlukem #define LDAP_DN_DESC_LEADCHAR(c) LDAP_ALPHA(c)
4312de962bdSlukem #define LDAP_DN_DESC_CHAR(c) LDAP_LDH(c)
4322de962bdSlukem #define LDAP_DN_LANG_SEP(c) ( (c) == ';' )
4332de962bdSlukem #define LDAP_DN_ATTRDESC_CHAR(c) \
4342de962bdSlukem ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
4352de962bdSlukem
4362de962bdSlukem /* special symbols */
4372de962bdSlukem #define LDAP_DN_AVA_EQUALS(c) ( (c) == '=' )
4382de962bdSlukem #define LDAP_DN_AVA_SEP(c) ( (c) == '+' )
4392de962bdSlukem #define LDAP_DN_RDN_SEP(c) ( (c) == ',' )
4402de962bdSlukem #define LDAP_DN_RDN_SEP_V2(c) ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
4412de962bdSlukem #define LDAP_DN_OCTOTHORPE(c) ( (c) == '#' )
4422de962bdSlukem #define LDAP_DN_QUOTES(c) ( (c) == '\"' )
4432de962bdSlukem #define LDAP_DN_ESCAPE(c) ( (c) == '\\' )
4442de962bdSlukem #define LDAP_DN_VALUE_END(c) \
4452de962bdSlukem ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
4462de962bdSlukem
4472de962bdSlukem /* NOTE: according to RFC 4514, '=' can be escaped and treated as special,
4482de962bdSlukem * i.e. escaped both as "\<hexpair>" and * as "\=", but it is treated as
4492de962bdSlukem * a regular char, i.e. it can also appear as '='.
4502de962bdSlukem *
4512de962bdSlukem * As such, in 2.2 we used to allow reading unescaped '=', but we always
4522de962bdSlukem * produced escaped '\3D'; this changes since 2.3, if compatibility issues
4532de962bdSlukem * do not arise
4542de962bdSlukem */
4552de962bdSlukem #define LDAP_DN_NE(c) \
4562de962bdSlukem ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
4572de962bdSlukem || LDAP_DN_QUOTES(c) \
4582de962bdSlukem || (c) == '<' || (c) == '>' )
4592de962bdSlukem #define LDAP_DN_MAYESCAPE(c) \
4602de962bdSlukem ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) \
4612de962bdSlukem || LDAP_DN_AVA_EQUALS(c) \
4622de962bdSlukem || LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) )
4632de962bdSlukem #define LDAP_DN_SHOULDESCAPE(c) ( LDAP_DN_AVA_EQUALS(c) )
4642de962bdSlukem
4652de962bdSlukem #define LDAP_DN_NEEDESCAPE(c) \
4662de962bdSlukem ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
4672de962bdSlukem #define LDAP_DN_NEEDESCAPE_LEAD(c) LDAP_DN_MAYESCAPE(c)
4682de962bdSlukem #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
4692de962bdSlukem ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
4702de962bdSlukem #define LDAP_DN_WILLESCAPE_CHAR(c) \
4712de962bdSlukem ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) || LDAP_DN_ESCAPE(c) )
4722de962bdSlukem #define LDAP_DN_IS_PRETTY(f) ( (f) & LDAP_DN_PRETTY )
4732de962bdSlukem #define LDAP_DN_WILLESCAPE_HEX(f, c) \
4742de962bdSlukem ( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
4752de962bdSlukem
4762de962bdSlukem /* LDAPv2 */
4772de962bdSlukem #define LDAP_DN_VALUE_END_V2(c) \
4782de962bdSlukem ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
4792de962bdSlukem /* RFC 1779 */
4802de962bdSlukem #define LDAP_DN_V2_SPECIAL(c) \
4812de962bdSlukem ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
4822de962bdSlukem || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
4832de962bdSlukem || LDAP_DN_OCTOTHORPE(c) )
4842de962bdSlukem #define LDAP_DN_V2_PAIR(c) \
4852de962bdSlukem ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
4862de962bdSlukem
4872de962bdSlukem /*
4882de962bdSlukem * DCE (mostly from Luke Howard and IBM implementation for AIX)
4892de962bdSlukem *
4902de962bdSlukem * From: "Application Development Guide - Directory Services" (FIXME: add link?)
4912de962bdSlukem * Here escapes and valid chars for GDS are considered; as soon as more
4922de962bdSlukem * specific info is found, the macros will be updated.
4932de962bdSlukem *
4942de962bdSlukem * Chars: 'a'-'z', 'A'-'Z', '0'-'9',
4952de962bdSlukem * '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
4962de962bdSlukem *
4972de962bdSlukem * Metachars: '/', ',', '=', '\'.
4982de962bdSlukem *
4992de962bdSlukem * the '\' is used to escape other metachars.
5002de962bdSlukem *
5012de962bdSlukem * Assertion: '='
5022de962bdSlukem * RDN separator: '/'
5032de962bdSlukem * AVA separator: ','
5042de962bdSlukem *
5052de962bdSlukem * Attribute types must start with alphabetic chars and can contain
5062de962bdSlukem * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
5072de962bdSlukem */
5082de962bdSlukem #define LDAP_DN_RDN_SEP_DCE(c) ( (c) == '/' )
5092de962bdSlukem #define LDAP_DN_AVA_SEP_DCE(c) ( (c) == ',' )
5102de962bdSlukem #define LDAP_DN_ESCAPE_DCE(c) ( LDAP_DN_ESCAPE(c) )
5112de962bdSlukem #define LDAP_DN_VALUE_END_DCE(c) \
5122de962bdSlukem ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
5132de962bdSlukem #define LDAP_DN_NEEDESCAPE_DCE(c) \
5142de962bdSlukem ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
5152de962bdSlukem
5162de962bdSlukem /* AD Canonical */
5172de962bdSlukem #define LDAP_DN_RDN_SEP_AD(c) ( (c) == '/' )
5182de962bdSlukem #define LDAP_DN_ESCAPE_AD(c) ( LDAP_DN_ESCAPE(c) )
5192de962bdSlukem #define LDAP_DN_AVA_SEP_AD(c) ( (c) == ',' ) /* assume same as DCE */
5202de962bdSlukem #define LDAP_DN_VALUE_END_AD(c) \
5212de962bdSlukem ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
5222de962bdSlukem #define LDAP_DN_NEEDESCAPE_AD(c) \
5232de962bdSlukem ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
5242de962bdSlukem
5252de962bdSlukem /* generics */
5262de962bdSlukem #define LDAP_DN_HEXPAIR(s) \
5272de962bdSlukem ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
5282de962bdSlukem /* better look at the AttributeDescription? */
5292de962bdSlukem
5302de962bdSlukem /* FIXME: no composite rdn or non-"dc" types, right?
5312de962bdSlukem * (what about "dc" in OID form?) */
5322de962bdSlukem /* FIXME: we do not allow binary values in domain, right? */
5332de962bdSlukem /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
5342de962bdSlukem /* NOTE: don't use strcasecmp() as it is locale specific! */
5352de962bdSlukem #define LDAP_DC_ATTR "dc"
5362de962bdSlukem #define LDAP_DC_ATTRU "DC"
5372de962bdSlukem #define LDAP_DN_IS_RDN_DC( r ) \
5382de962bdSlukem ( (r) && (r)[0] && !(r)[1] \
5392de962bdSlukem && ((r)[0]->la_flags & LDAP_AVA_STRING) \
5402de962bdSlukem && ((r)[0]->la_attr.bv_len == 2) \
5412de962bdSlukem && (((r)[0]->la_attr.bv_val[0] == LDAP_DC_ATTR[0]) \
5422de962bdSlukem || ((r)[0]->la_attr.bv_val[0] == LDAP_DC_ATTRU[0])) \
5432de962bdSlukem && (((r)[0]->la_attr.bv_val[1] == LDAP_DC_ATTR[1]) \
5442de962bdSlukem || ((r)[0]->la_attr.bv_val[1] == LDAP_DC_ATTRU[1])))
5452de962bdSlukem
5462de962bdSlukem /* Composite rules */
5472de962bdSlukem #define LDAP_DN_ALLOW_ONE_SPACE(f) \
5482de962bdSlukem ( LDAP_DN_LDAPV2(f) \
5492de962bdSlukem || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
5502de962bdSlukem #define LDAP_DN_ALLOW_SPACES(f) \
5512de962bdSlukem ( LDAP_DN_LDAPV2(f) \
5522de962bdSlukem || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
5532de962bdSlukem #define LDAP_DN_LDAP(f) \
5542de962bdSlukem ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
5552de962bdSlukem #define LDAP_DN_LDAPV3(f) \
5562de962bdSlukem ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
5572de962bdSlukem #define LDAP_DN_LDAPV2(f) \
5582de962bdSlukem ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
5592de962bdSlukem #define LDAP_DN_DCE(f) \
5602de962bdSlukem ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
5612de962bdSlukem #define LDAP_DN_UFN(f) \
5622de962bdSlukem ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
5632de962bdSlukem #define LDAP_DN_ADC(f) \
5642de962bdSlukem ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
5652de962bdSlukem #define LDAP_DN_FORMAT(f) ( (f) & LDAP_DN_FORMAT_MASK )
5662de962bdSlukem
5672de962bdSlukem /*
5682de962bdSlukem * LDAPAVA helpers (will become part of the API for operations
5692de962bdSlukem * on structural representations of DNs).
5702de962bdSlukem */
5712de962bdSlukem static LDAPAVA *
ldapava_new(const struct berval * attr,const struct berval * val,unsigned flags,void * ctx)5722de962bdSlukem ldapava_new( const struct berval *attr, const struct berval *val,
5732de962bdSlukem unsigned flags, void *ctx )
5742de962bdSlukem {
5752de962bdSlukem LDAPAVA *ava;
5762de962bdSlukem
5772de962bdSlukem assert( attr != NULL );
5782de962bdSlukem assert( val != NULL );
5792de962bdSlukem
5802de962bdSlukem ava = LDAP_MALLOCX( sizeof( LDAPAVA ) + attr->bv_len + 1, ctx );
5812de962bdSlukem
5822de962bdSlukem if ( ava ) {
5832de962bdSlukem ava->la_attr.bv_len = attr->bv_len;
5842de962bdSlukem ava->la_attr.bv_val = (char *)(ava+1);
5852de962bdSlukem AC_MEMCPY( ava->la_attr.bv_val, attr->bv_val, attr->bv_len );
5862de962bdSlukem ava->la_attr.bv_val[attr->bv_len] = '\0';
5872de962bdSlukem
5882de962bdSlukem ava->la_value = *val;
5892de962bdSlukem ava->la_flags = flags | LDAP_AVA_FREE_VALUE;
5902de962bdSlukem
5912de962bdSlukem ava->la_private = NULL;
5922de962bdSlukem }
5932de962bdSlukem
5942de962bdSlukem return( ava );
5952de962bdSlukem }
5962de962bdSlukem
597d11b170bStron static void
ldapava_free(LDAPAVA * ava,void * ctx)5982de962bdSlukem ldapava_free( LDAPAVA *ava, void *ctx )
5992de962bdSlukem {
6002de962bdSlukem assert( ava != NULL );
6012de962bdSlukem
6022de962bdSlukem #if 0
6032de962bdSlukem /* ava's private must be freed by caller
6042de962bdSlukem * (at present let's skip this check because la_private
6052de962bdSlukem * basically holds static data) */
6062de962bdSlukem assert( ava->la_private == NULL );
6072de962bdSlukem #endif
6082de962bdSlukem
6092de962bdSlukem if (ava->la_flags & LDAP_AVA_FREE_VALUE)
6102de962bdSlukem LDAP_FREEX( ava->la_value.bv_val, ctx );
6112de962bdSlukem
6122de962bdSlukem LDAP_FREEX( ava, ctx );
6132de962bdSlukem }
6142de962bdSlukem
6152de962bdSlukem void
ldap_rdnfree(LDAPRDN rdn)6162de962bdSlukem ldap_rdnfree( LDAPRDN rdn )
6172de962bdSlukem {
6182de962bdSlukem ldap_rdnfree_x( rdn, NULL );
6192de962bdSlukem }
6202de962bdSlukem
6212de962bdSlukem void
ldap_rdnfree_x(LDAPRDN rdn,void * ctx)6222de962bdSlukem ldap_rdnfree_x( LDAPRDN rdn, void *ctx )
6232de962bdSlukem {
6242de962bdSlukem int iAVA;
6252de962bdSlukem
6262de962bdSlukem if ( rdn == NULL ) {
6272de962bdSlukem return;
6282de962bdSlukem }
6292de962bdSlukem
6302de962bdSlukem for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
6312de962bdSlukem ldapava_free( rdn[ iAVA ], ctx );
6322de962bdSlukem }
6332de962bdSlukem
6342de962bdSlukem LDAP_FREEX( rdn, ctx );
6352de962bdSlukem }
6362de962bdSlukem
6372de962bdSlukem void
ldap_dnfree(LDAPDN dn)6382de962bdSlukem ldap_dnfree( LDAPDN dn )
6392de962bdSlukem {
6402de962bdSlukem ldap_dnfree_x( dn, NULL );
6412de962bdSlukem }
6422de962bdSlukem
6432de962bdSlukem void
ldap_dnfree_x(LDAPDN dn,void * ctx)6442de962bdSlukem ldap_dnfree_x( LDAPDN dn, void *ctx )
6452de962bdSlukem {
6462de962bdSlukem int iRDN;
6472de962bdSlukem
6482de962bdSlukem if ( dn == NULL ) {
6492de962bdSlukem return;
6502de962bdSlukem }
6512de962bdSlukem
6522de962bdSlukem for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
6532de962bdSlukem ldap_rdnfree_x( dn[ iRDN ], ctx );
6542de962bdSlukem }
6552de962bdSlukem
6562de962bdSlukem LDAP_FREEX( dn, ctx );
6572de962bdSlukem }
6582de962bdSlukem
6592de962bdSlukem /*
6602de962bdSlukem * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
6612de962bdSlukem * into a structural representation of the DN, by separating attribute
6622de962bdSlukem * types and values encoded in the more appropriate form, which is
6632de962bdSlukem * string or OID for attribute types and binary form of the BER encoded
6642de962bdSlukem * value or Unicode string. Formats different from LDAPv3 are parsed
6652de962bdSlukem * according to their own rules and turned into the more appropriate
6662de962bdSlukem * form according to LDAPv3.
6672de962bdSlukem *
6682de962bdSlukem * NOTE: I realize the code is getting spaghettish; it is rather
6692de962bdSlukem * experimental and will hopefully turn into something more simple
6702de962bdSlukem * and readable as soon as it works as expected.
6712de962bdSlukem */
6722de962bdSlukem
6732de962bdSlukem /*
6742de962bdSlukem * Default sizes of AVA and RDN static working arrays; if required
6752de962bdSlukem * the are dynamically resized. The values can be tuned in case
6762de962bdSlukem * of special requirements (e.g. very deep DN trees or high number
6772de962bdSlukem * of AVAs per RDN).
6782de962bdSlukem */
6792de962bdSlukem #define TMP_AVA_SLOTS 8
6802de962bdSlukem #define TMP_RDN_SLOTS 32
6812de962bdSlukem
6822de962bdSlukem int
ldap_str2dn(LDAP_CONST char * str,LDAPDN * dn,unsigned flags)6832de962bdSlukem ldap_str2dn( LDAP_CONST char *str, LDAPDN *dn, unsigned flags )
6842de962bdSlukem {
6852de962bdSlukem struct berval bv;
6862de962bdSlukem
6872de962bdSlukem assert( str != NULL );
6882de962bdSlukem
6892de962bdSlukem bv.bv_len = strlen( str );
6902de962bdSlukem bv.bv_val = (char *) str;
6912de962bdSlukem
6922de962bdSlukem return ldap_bv2dn_x( &bv, dn, flags, NULL );
6932de962bdSlukem }
6942de962bdSlukem
6952de962bdSlukem int
ldap_bv2dn(struct berval * bv,LDAPDN * dn,unsigned flags)6962de962bdSlukem ldap_bv2dn( struct berval *bv, LDAPDN *dn, unsigned flags )
6972de962bdSlukem {
6982de962bdSlukem return ldap_bv2dn_x( bv, dn, flags, NULL );
6992de962bdSlukem }
7002de962bdSlukem
7012de962bdSlukem int
ldap_bv2dn_x(struct berval * bvin,LDAPDN * dn,unsigned flags,void * ctx)7022de962bdSlukem ldap_bv2dn_x( struct berval *bvin, LDAPDN *dn, unsigned flags, void *ctx )
7032de962bdSlukem {
7042de962bdSlukem const char *p;
7052de962bdSlukem int rc = LDAP_DECODING_ERROR;
7062de962bdSlukem int nrdns = 0;
7072de962bdSlukem
7082de962bdSlukem LDAPDN newDN = NULL;
7092de962bdSlukem LDAPRDN newRDN = NULL, tmpDN_[TMP_RDN_SLOTS], *tmpDN = tmpDN_;
7102de962bdSlukem int num_slots = TMP_RDN_SLOTS;
7112de962bdSlukem char *str, *end;
7122de962bdSlukem struct berval bvtmp, *bv = &bvtmp;
7132de962bdSlukem
7142de962bdSlukem assert( bvin != NULL );
7152de962bdSlukem assert( bvin->bv_val != NULL );
7162de962bdSlukem assert( dn != NULL );
7172de962bdSlukem
7182de962bdSlukem *bv = *bvin;
7192de962bdSlukem str = bv->bv_val;
7202de962bdSlukem end = str + bv->bv_len;
7212de962bdSlukem
722*549b59edSchristos Debug2( LDAP_DEBUG_ARGS, "=> ldap_bv2dn(%s,%u)\n", str, flags );
7232de962bdSlukem
7242de962bdSlukem *dn = NULL;
7252de962bdSlukem
7262de962bdSlukem switch ( LDAP_DN_FORMAT( flags ) ) {
7272de962bdSlukem case LDAP_DN_FORMAT_LDAP:
7282de962bdSlukem case LDAP_DN_FORMAT_LDAPV3:
7292de962bdSlukem case LDAP_DN_FORMAT_DCE:
7302de962bdSlukem break;
7312de962bdSlukem
7322de962bdSlukem /* allow DN enclosed in brackets */
7332de962bdSlukem case LDAP_DN_FORMAT_LDAPV2:
7342de962bdSlukem if ( str[0] == '<' ) {
7352de962bdSlukem if ( bv->bv_len < 2 || end[ -1 ] != '>' ) {
7362de962bdSlukem rc = LDAP_DECODING_ERROR;
7372de962bdSlukem goto parsing_error;
7382de962bdSlukem }
7392de962bdSlukem bv->bv_val++;
7402de962bdSlukem bv->bv_len -= 2;
7412de962bdSlukem str++;
7422de962bdSlukem end--;
7432de962bdSlukem }
7442de962bdSlukem break;
7452de962bdSlukem
7462de962bdSlukem /* unsupported in str2dn */
7472de962bdSlukem case LDAP_DN_FORMAT_UFN:
7482de962bdSlukem case LDAP_DN_FORMAT_AD_CANONICAL:
7492de962bdSlukem return LDAP_PARAM_ERROR;
7502de962bdSlukem
7512de962bdSlukem case LDAP_DN_FORMAT_LBER:
7522de962bdSlukem default:
7532de962bdSlukem return LDAP_PARAM_ERROR;
7542de962bdSlukem }
7552de962bdSlukem
7562de962bdSlukem if ( bv->bv_len == 0 ) {
7572de962bdSlukem return LDAP_SUCCESS;
7582de962bdSlukem }
7592de962bdSlukem
7602de962bdSlukem if( memchr( bv->bv_val, '\0', bv->bv_len ) != NULL ) {
7612de962bdSlukem /* value must have embedded NULs */
7622de962bdSlukem return LDAP_DECODING_ERROR;
7632de962bdSlukem }
7642de962bdSlukem
7652de962bdSlukem p = str;
7662de962bdSlukem if ( LDAP_DN_DCE( flags ) ) {
7672de962bdSlukem
7682de962bdSlukem /*
7692de962bdSlukem * (from Luke Howard: thnx) A RDN separator is required
7702de962bdSlukem * at the beginning of an (absolute) DN.
7712de962bdSlukem */
7722de962bdSlukem if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
7732de962bdSlukem goto parsing_error;
7742de962bdSlukem }
7752de962bdSlukem p++;
7762de962bdSlukem
7772de962bdSlukem /*
7782de962bdSlukem * actually we do not want to accept by default the DCE form,
7792de962bdSlukem * we do not want to auto-detect it
7802de962bdSlukem */
7812de962bdSlukem #if 0
7822de962bdSlukem } else if ( LDAP_DN_LDAP( flags ) ) {
7832de962bdSlukem /*
7842de962bdSlukem * if dn starts with '/' let's make it a DCE dn
7852de962bdSlukem */
7862de962bdSlukem if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
7872de962bdSlukem flags |= LDAP_DN_FORMAT_DCE;
7882de962bdSlukem p++;
7892de962bdSlukem }
7902de962bdSlukem #endif
7912de962bdSlukem }
7922de962bdSlukem
7932de962bdSlukem for ( ; p < end; p++ ) {
7942de962bdSlukem int err;
7952de962bdSlukem struct berval tmpbv;
7962de962bdSlukem tmpbv.bv_len = bv->bv_len - ( p - str );
7972de962bdSlukem tmpbv.bv_val = (char *)p;
7982de962bdSlukem
7992de962bdSlukem err = ldap_bv2rdn_x( &tmpbv, &newRDN, (char **) &p, flags,ctx);
8002de962bdSlukem if ( err != LDAP_SUCCESS ) {
8012de962bdSlukem goto parsing_error;
8022de962bdSlukem }
8032de962bdSlukem
8042de962bdSlukem /*
8052de962bdSlukem * We expect a rdn separator
8062de962bdSlukem */
8072de962bdSlukem if ( p < end && p[ 0 ] ) {
8082de962bdSlukem switch ( LDAP_DN_FORMAT( flags ) ) {
8092de962bdSlukem case LDAP_DN_FORMAT_LDAPV3:
8102de962bdSlukem if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
8112de962bdSlukem rc = LDAP_DECODING_ERROR;
8122de962bdSlukem goto parsing_error;
8132de962bdSlukem }
8142de962bdSlukem break;
8152de962bdSlukem
8162de962bdSlukem case LDAP_DN_FORMAT_LDAP:
8172de962bdSlukem case LDAP_DN_FORMAT_LDAPV2:
8182de962bdSlukem if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
8192de962bdSlukem rc = LDAP_DECODING_ERROR;
8202de962bdSlukem goto parsing_error;
8212de962bdSlukem }
8222de962bdSlukem break;
8232de962bdSlukem
8242de962bdSlukem case LDAP_DN_FORMAT_DCE:
8252de962bdSlukem if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
8262de962bdSlukem rc = LDAP_DECODING_ERROR;
8272de962bdSlukem goto parsing_error;
8282de962bdSlukem }
8292de962bdSlukem break;
8302de962bdSlukem }
8312de962bdSlukem }
8322de962bdSlukem
8332de962bdSlukem
8342de962bdSlukem tmpDN[nrdns++] = newRDN;
8352de962bdSlukem newRDN = NULL;
8362de962bdSlukem
8372de962bdSlukem /*
8382de962bdSlukem * make the static RDN array dynamically rescalable
8392de962bdSlukem */
8402de962bdSlukem if ( nrdns == num_slots ) {
8412de962bdSlukem LDAPRDN *tmp;
8422de962bdSlukem
8432de962bdSlukem if ( tmpDN == tmpDN_ ) {
8442de962bdSlukem tmp = LDAP_MALLOCX( num_slots * 2 * sizeof( LDAPRDN * ), ctx );
8452de962bdSlukem if ( tmp == NULL ) {
8462de962bdSlukem rc = LDAP_NO_MEMORY;
8472de962bdSlukem goto parsing_error;
8482de962bdSlukem }
8492de962bdSlukem AC_MEMCPY( tmp, tmpDN, num_slots * sizeof( LDAPRDN * ) );
8502de962bdSlukem
8512de962bdSlukem } else {
8522de962bdSlukem tmp = LDAP_REALLOCX( tmpDN, num_slots * 2 * sizeof( LDAPRDN * ), ctx );
8532de962bdSlukem if ( tmp == NULL ) {
8542de962bdSlukem rc = LDAP_NO_MEMORY;
8552de962bdSlukem goto parsing_error;
8562de962bdSlukem }
8572de962bdSlukem }
8582de962bdSlukem
8592de962bdSlukem tmpDN = tmp;
8602de962bdSlukem num_slots *= 2;
8612de962bdSlukem }
8622de962bdSlukem
8632de962bdSlukem if ( p >= end || p[ 0 ] == '\0' ) {
8642de962bdSlukem /*
8652de962bdSlukem * the DN is over, phew
8662de962bdSlukem */
8672de962bdSlukem newDN = (LDAPDN)LDAP_MALLOCX( sizeof(LDAPRDN *) * (nrdns+1), ctx );
8682de962bdSlukem if ( newDN == NULL ) {
8692de962bdSlukem rc = LDAP_NO_MEMORY;
8702de962bdSlukem goto parsing_error;
8712de962bdSlukem } else {
8722de962bdSlukem int i;
8732de962bdSlukem
8742de962bdSlukem if ( LDAP_DN_DCE( flags ) ) {
8752de962bdSlukem /* add in reversed order */
8762de962bdSlukem for ( i=0; i<nrdns; i++ )
8772de962bdSlukem newDN[i] = tmpDN[nrdns-1-i];
8782de962bdSlukem } else {
8792de962bdSlukem for ( i=0; i<nrdns; i++ )
8802de962bdSlukem newDN[i] = tmpDN[i];
8812de962bdSlukem }
8822de962bdSlukem newDN[nrdns] = NULL;
8832de962bdSlukem rc = LDAP_SUCCESS;
8842de962bdSlukem }
8852de962bdSlukem goto return_result;
8862de962bdSlukem }
8872de962bdSlukem }
8882de962bdSlukem
8892de962bdSlukem parsing_error:;
8902de962bdSlukem if ( newRDN ) {
8912de962bdSlukem ldap_rdnfree_x( newRDN, ctx );
8922de962bdSlukem }
8932de962bdSlukem
8942de962bdSlukem for ( nrdns-- ;nrdns >= 0; nrdns-- ) {
8952de962bdSlukem ldap_rdnfree_x( tmpDN[nrdns], ctx );
8962de962bdSlukem }
8972de962bdSlukem
8982de962bdSlukem return_result:;
8992de962bdSlukem
9002de962bdSlukem if ( tmpDN != tmpDN_ ) {
9012de962bdSlukem LDAP_FREEX( tmpDN, ctx );
9022de962bdSlukem }
9032de962bdSlukem
904*549b59edSchristos Debug3( LDAP_DEBUG_ARGS, "<= ldap_bv2dn(%s)=%d %s\n", str, rc,
9052de962bdSlukem rc ? ldap_err2string( rc ) : "" );
9062de962bdSlukem *dn = newDN;
9072de962bdSlukem
9082de962bdSlukem return( rc );
9092de962bdSlukem }
9102de962bdSlukem
9112de962bdSlukem /*
9122de962bdSlukem * ldap_str2rdn
9132de962bdSlukem *
9142de962bdSlukem * Parses a relative DN according to flags up to a rdn separator
9152de962bdSlukem * or to the end of str.
9162de962bdSlukem * Returns the rdn and a pointer to the string continuation, which
9172de962bdSlukem * corresponds to the rdn separator or to '\0' in case the string is over.
9182de962bdSlukem */
9192de962bdSlukem int
ldap_str2rdn(LDAP_CONST char * str,LDAPRDN * rdn,char ** n_in,unsigned flags)9202de962bdSlukem ldap_str2rdn( LDAP_CONST char *str, LDAPRDN *rdn,
9212de962bdSlukem char **n_in, unsigned flags )
9222de962bdSlukem {
9232de962bdSlukem struct berval bv;
9242de962bdSlukem
9252de962bdSlukem assert( str != NULL );
9262de962bdSlukem assert( str[ 0 ] != '\0' ); /* FIXME: is this required? */
9272de962bdSlukem
9282de962bdSlukem bv.bv_len = strlen( str );
9292de962bdSlukem bv.bv_val = (char *) str;
9302de962bdSlukem
9312de962bdSlukem return ldap_bv2rdn_x( &bv, rdn, n_in, flags, NULL );
9322de962bdSlukem }
9332de962bdSlukem
9342de962bdSlukem int
ldap_bv2rdn(struct berval * bv,LDAPRDN * rdn,char ** n_in,unsigned flags)9352de962bdSlukem ldap_bv2rdn( struct berval *bv, LDAPRDN *rdn,
9362de962bdSlukem char **n_in, unsigned flags )
9372de962bdSlukem {
9382de962bdSlukem return ldap_bv2rdn_x( bv, rdn, n_in, flags, NULL );
9392de962bdSlukem }
9402de962bdSlukem
9412de962bdSlukem int
ldap_bv2rdn_x(struct berval * bv,LDAPRDN * rdn,char ** n_in,unsigned flags,void * ctx)9422de962bdSlukem ldap_bv2rdn_x( struct berval *bv, LDAPRDN *rdn,
9432de962bdSlukem char **n_in, unsigned flags, void *ctx )
9442de962bdSlukem {
9452de962bdSlukem const char **n = (const char **) n_in;
9462de962bdSlukem const char *p;
9472de962bdSlukem int navas = 0;
9482de962bdSlukem int state = B4AVA;
9492de962bdSlukem int rc = LDAP_DECODING_ERROR;
9502de962bdSlukem int attrTypeEncoding = LDAP_AVA_STRING,
9512de962bdSlukem attrValueEncoding = LDAP_AVA_STRING;
9522de962bdSlukem
9532de962bdSlukem struct berval attrType = BER_BVNULL;
9542de962bdSlukem struct berval attrValue = BER_BVNULL;
9552de962bdSlukem
9562de962bdSlukem LDAPRDN newRDN = NULL;
9572de962bdSlukem LDAPAVA *tmpRDN_[TMP_AVA_SLOTS], **tmpRDN = tmpRDN_;
9582de962bdSlukem int num_slots = TMP_AVA_SLOTS;
9592de962bdSlukem
9602de962bdSlukem char *str;
9612de962bdSlukem ber_len_t stoplen;
9622de962bdSlukem
9632de962bdSlukem assert( bv != NULL );
9642de962bdSlukem assert( bv->bv_len != 0 );
9652de962bdSlukem assert( bv->bv_val != NULL );
9662de962bdSlukem assert( rdn || flags & LDAP_DN_SKIP );
9672de962bdSlukem assert( n != NULL );
9682de962bdSlukem
9692de962bdSlukem str = bv->bv_val;
9702de962bdSlukem stoplen = bv->bv_len;
9712de962bdSlukem
9722de962bdSlukem if ( rdn ) {
9732de962bdSlukem *rdn = NULL;
9742de962bdSlukem }
9752de962bdSlukem *n = NULL;
9762de962bdSlukem
9772de962bdSlukem switch ( LDAP_DN_FORMAT( flags ) ) {
9782de962bdSlukem case LDAP_DN_FORMAT_LDAP:
9792de962bdSlukem case LDAP_DN_FORMAT_LDAPV3:
9802de962bdSlukem case LDAP_DN_FORMAT_LDAPV2:
9812de962bdSlukem case LDAP_DN_FORMAT_DCE:
9822de962bdSlukem break;
9832de962bdSlukem
9842de962bdSlukem /* unsupported in str2dn */
9852de962bdSlukem case LDAP_DN_FORMAT_UFN:
9862de962bdSlukem case LDAP_DN_FORMAT_AD_CANONICAL:
9872de962bdSlukem return LDAP_PARAM_ERROR;
9882de962bdSlukem
9892de962bdSlukem case LDAP_DN_FORMAT_LBER:
9902de962bdSlukem default:
9912de962bdSlukem return LDAP_PARAM_ERROR;
9922de962bdSlukem }
9932de962bdSlukem
9942de962bdSlukem if ( bv->bv_len == 0 ) {
9952de962bdSlukem return LDAP_SUCCESS;
9962de962bdSlukem
9972de962bdSlukem }
9982de962bdSlukem
9992de962bdSlukem if( memchr( bv->bv_val, '\0', bv->bv_len ) != NULL ) {
10002de962bdSlukem /* value must have embedded NULs */
10012de962bdSlukem return LDAP_DECODING_ERROR;
10022de962bdSlukem }
10032de962bdSlukem
10042de962bdSlukem p = str;
10052de962bdSlukem for ( ; p[ 0 ] || state == GOTAVA; ) {
10062de962bdSlukem
10072de962bdSlukem /*
10082de962bdSlukem * The parser in principle advances one token a time,
10092de962bdSlukem * or toggles state if preferable.
10102de962bdSlukem */
10112de962bdSlukem switch (state) {
10122de962bdSlukem
10132de962bdSlukem /*
10142de962bdSlukem * an AttributeType can be encoded as:
10152de962bdSlukem * - its string representation; in detail, implementations
10162de962bdSlukem * MUST recognize AttributeType string type names listed
10172de962bdSlukem * in Section 3 of RFC 4514, and MAY recognize other names.
10182de962bdSlukem * - its numeric OID (a dotted decimal string)
10192de962bdSlukem */
10202de962bdSlukem case B4AVA:
10212de962bdSlukem if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
10222de962bdSlukem if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
10232de962bdSlukem /* error */
10242de962bdSlukem goto parsing_error;
10252de962bdSlukem }
10262de962bdSlukem p++;
10272de962bdSlukem }
10282de962bdSlukem
10292de962bdSlukem if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
10302de962bdSlukem if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
10312de962bdSlukem /* error */
10322de962bdSlukem goto parsing_error;
10332de962bdSlukem }
10342de962bdSlukem
10352de962bdSlukem /* whitespace is allowed (and trimmed) */
10362de962bdSlukem p++;
10372de962bdSlukem while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
10382de962bdSlukem p++;
10392de962bdSlukem }
10402de962bdSlukem
10412de962bdSlukem if ( !p[ 0 ] ) {
10422de962bdSlukem /* error: we expected an AVA */
10432de962bdSlukem goto parsing_error;
10442de962bdSlukem }
10452de962bdSlukem }
10462de962bdSlukem
10472de962bdSlukem /* oid */
10482de962bdSlukem if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
10492de962bdSlukem state = B4OIDATTRTYPE;
10502de962bdSlukem break;
10512de962bdSlukem }
10522de962bdSlukem
10532de962bdSlukem /* else must be alpha */
10542de962bdSlukem if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
10552de962bdSlukem goto parsing_error;
10562de962bdSlukem }
10572de962bdSlukem
10582de962bdSlukem /* LDAPv2 "oid." prefix */
10592de962bdSlukem if ( LDAP_DN_LDAPV2( flags ) ) {
10602de962bdSlukem /*
10612de962bdSlukem * to be overly pedantic, we only accept
10622de962bdSlukem * "OID." or "oid."
10632de962bdSlukem */
10642de962bdSlukem if ( flags & LDAP_DN_PEDANTIC ) {
10652de962bdSlukem if ( !strncmp( p, "OID.", 4 )
10662de962bdSlukem || !strncmp( p, "oid.", 4 ) ) {
10672de962bdSlukem p += 4;
10682de962bdSlukem state = B4OIDATTRTYPE;
10692de962bdSlukem break;
10702de962bdSlukem }
10712de962bdSlukem } else {
10722de962bdSlukem if ( !strncasecmp( p, "oid.", 4 ) ) {
10732de962bdSlukem p += 4;
10742de962bdSlukem state = B4OIDATTRTYPE;
10752de962bdSlukem break;
10762de962bdSlukem }
10772de962bdSlukem }
10782de962bdSlukem }
10792de962bdSlukem
10802de962bdSlukem state = B4STRINGATTRTYPE;
10812de962bdSlukem break;
10822de962bdSlukem
10832de962bdSlukem case B4OIDATTRTYPE: {
10842de962bdSlukem int err = LDAP_SUCCESS;
10852de962bdSlukem
10862de962bdSlukem attrType.bv_val = ldap_int_parse_numericoid( &p, &err,
10872de962bdSlukem LDAP_SCHEMA_SKIP);
10882de962bdSlukem
10892de962bdSlukem if ( err != LDAP_SUCCESS ) {
10902de962bdSlukem goto parsing_error;
10912de962bdSlukem }
10922de962bdSlukem attrType.bv_len = p - attrType.bv_val;
10932de962bdSlukem
10942de962bdSlukem attrTypeEncoding = LDAP_AVA_BINARY;
10952de962bdSlukem
10962de962bdSlukem state = B4AVAEQUALS;
10972de962bdSlukem break;
10982de962bdSlukem }
10992de962bdSlukem
11002de962bdSlukem case B4STRINGATTRTYPE: {
11012de962bdSlukem const char *startPos, *endPos = NULL;
11022de962bdSlukem ber_len_t len;
11032de962bdSlukem
11042de962bdSlukem /*
11052de962bdSlukem * the starting char has been found to be
11062de962bdSlukem * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
11072de962bdSlukem * FIXME: DCE attr types seem to have a more
11082de962bdSlukem * restrictive syntax (no '-' ...)
11092de962bdSlukem */
11102de962bdSlukem for ( startPos = p++; p[ 0 ]; p++ ) {
11112de962bdSlukem if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
11122de962bdSlukem continue;
11132de962bdSlukem }
11142de962bdSlukem
11152de962bdSlukem if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
11162de962bdSlukem
11172de962bdSlukem /*
11182de962bdSlukem * RFC 4514 explicitly does not allow attribute
11192de962bdSlukem * description options, such as language tags.
11202de962bdSlukem */
11212de962bdSlukem if ( flags & LDAP_DN_PEDANTIC ) {
11222de962bdSlukem goto parsing_error;
11232de962bdSlukem }
11242de962bdSlukem
11252de962bdSlukem /*
11262de962bdSlukem * we trim ';' and following lang
11272de962bdSlukem * and so from attribute types
11282de962bdSlukem */
11292de962bdSlukem endPos = p;
11302de962bdSlukem for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
11312de962bdSlukem || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
11322de962bdSlukem /* no op */ ;
11332de962bdSlukem }
11342de962bdSlukem break;
11352de962bdSlukem }
11362de962bdSlukem break;
11372de962bdSlukem }
11382de962bdSlukem
11392de962bdSlukem len = ( endPos ? endPos : p ) - startPos;
11402de962bdSlukem if ( len == 0 ) {
11412de962bdSlukem goto parsing_error;
11422de962bdSlukem }
11432de962bdSlukem
11442de962bdSlukem attrTypeEncoding = LDAP_AVA_STRING;
11452de962bdSlukem
11462de962bdSlukem /*
11472de962bdSlukem * here we need to decide whether to use it as is
11482de962bdSlukem * or turn it in OID form; as a consequence, we
11492de962bdSlukem * need to decide whether to binary encode the value
11502de962bdSlukem */
11512de962bdSlukem
11522de962bdSlukem state = B4AVAEQUALS;
11532de962bdSlukem
11542de962bdSlukem if ( flags & LDAP_DN_SKIP ) {
11552de962bdSlukem break;
11562de962bdSlukem }
11572de962bdSlukem
11582de962bdSlukem attrType.bv_val = (char *)startPos;
11592de962bdSlukem attrType.bv_len = len;
11602de962bdSlukem
11612de962bdSlukem break;
11622de962bdSlukem }
11632de962bdSlukem
11642de962bdSlukem case B4AVAEQUALS:
11652de962bdSlukem /* spaces may not be allowed */
11662de962bdSlukem if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
11672de962bdSlukem if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
11682de962bdSlukem goto parsing_error;
11692de962bdSlukem }
11702de962bdSlukem
11712de962bdSlukem /* trim spaces */
11722de962bdSlukem for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
11732de962bdSlukem /* no op */
11742de962bdSlukem }
11752de962bdSlukem }
11762de962bdSlukem
11772de962bdSlukem /* need equal sign */
11782de962bdSlukem if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
11792de962bdSlukem goto parsing_error;
11802de962bdSlukem }
11812de962bdSlukem p++;
11822de962bdSlukem
11832de962bdSlukem /* spaces may not be allowed */
11842de962bdSlukem if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
11852de962bdSlukem if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
11862de962bdSlukem goto parsing_error;
11872de962bdSlukem }
11882de962bdSlukem
11892de962bdSlukem /* trim spaces */
11902de962bdSlukem for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
11912de962bdSlukem /* no op */
11922de962bdSlukem }
11932de962bdSlukem }
11942de962bdSlukem
11952de962bdSlukem /*
11962de962bdSlukem * octothorpe means a BER encoded value will follow
11972de962bdSlukem * FIXME: I don't think DCE will allow it
11982de962bdSlukem */
11992de962bdSlukem if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
12002de962bdSlukem p++;
12012de962bdSlukem attrValueEncoding = LDAP_AVA_BINARY;
12022de962bdSlukem state = B4BINARYVALUE;
12032de962bdSlukem break;
12042de962bdSlukem }
12052de962bdSlukem
12062de962bdSlukem /* STRING value expected */
12072de962bdSlukem
12082de962bdSlukem /*
12092de962bdSlukem * if we're pedantic, an attribute type in OID form
12102de962bdSlukem * SHOULD imply a BER encoded attribute value; we
12112de962bdSlukem * should at least issue a warning
12122de962bdSlukem */
12132de962bdSlukem if ( ( flags & LDAP_DN_PEDANTIC )
12142de962bdSlukem && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
12152de962bdSlukem /* OID attrType SHOULD use binary encoding */
12162de962bdSlukem goto parsing_error;
12172de962bdSlukem }
12182de962bdSlukem
12192de962bdSlukem attrValueEncoding = LDAP_AVA_STRING;
12202de962bdSlukem
12212de962bdSlukem /*
12222de962bdSlukem * LDAPv2 allows the attribute value to be quoted;
12232de962bdSlukem * also, IA5 values are expected, in principle
12242de962bdSlukem */
12252de962bdSlukem if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
12262de962bdSlukem if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
12272de962bdSlukem p++;
12282de962bdSlukem state = B4IA5VALUEQUOTED;
12292de962bdSlukem break;
12302de962bdSlukem }
12312de962bdSlukem
12322de962bdSlukem if ( LDAP_DN_LDAPV2( flags ) ) {
12332de962bdSlukem state = B4IA5VALUE;
12342de962bdSlukem break;
12352de962bdSlukem }
12362de962bdSlukem }
12372de962bdSlukem
12382de962bdSlukem /*
12392de962bdSlukem * here STRING means RFC 4514 string
12402de962bdSlukem * FIXME: what about DCE strings?
12412de962bdSlukem */
12422de962bdSlukem if ( !p[ 0 ] ) {
12432de962bdSlukem /* empty value */
12442de962bdSlukem state = GOTAVA;
12452de962bdSlukem } else {
12462de962bdSlukem state = B4STRINGVALUE;
12472de962bdSlukem }
12482de962bdSlukem break;
12492de962bdSlukem
12502de962bdSlukem case B4BINARYVALUE:
12512de962bdSlukem if ( hexstr2binval( p, &attrValue, &p, flags, ctx ) ) {
12522de962bdSlukem goto parsing_error;
12532de962bdSlukem }
12542de962bdSlukem
12552de962bdSlukem state = GOTAVA;
12562de962bdSlukem break;
12572de962bdSlukem
12582de962bdSlukem case B4STRINGVALUE:
12592de962bdSlukem switch ( LDAP_DN_FORMAT( flags ) ) {
12602de962bdSlukem case LDAP_DN_FORMAT_LDAP:
12612de962bdSlukem case LDAP_DN_FORMAT_LDAPV3:
12622de962bdSlukem if ( str2strval( p, stoplen - ( p - str ),
12632de962bdSlukem &attrValue, &p, flags,
12642de962bdSlukem &attrValueEncoding, ctx ) ) {
12652de962bdSlukem goto parsing_error;
12662de962bdSlukem }
12672de962bdSlukem break;
12682de962bdSlukem
12692de962bdSlukem case LDAP_DN_FORMAT_DCE:
12702de962bdSlukem if ( DCE2strval( p, &attrValue, &p, flags, ctx ) ) {
12712de962bdSlukem goto parsing_error;
12722de962bdSlukem }
12732de962bdSlukem break;
12742de962bdSlukem
12752de962bdSlukem default:
12762de962bdSlukem assert( 0 );
12772de962bdSlukem }
12782de962bdSlukem
12792de962bdSlukem state = GOTAVA;
12802de962bdSlukem break;
12812de962bdSlukem
12822de962bdSlukem case B4IA5VALUE:
12832de962bdSlukem if ( IA52strval( p, &attrValue, &p, flags, ctx ) ) {
12842de962bdSlukem goto parsing_error;
12852de962bdSlukem }
12862de962bdSlukem
12872de962bdSlukem state = GOTAVA;
12882de962bdSlukem break;
12892de962bdSlukem
12902de962bdSlukem case B4IA5VALUEQUOTED:
12912de962bdSlukem
12922de962bdSlukem /* lead quote already stripped */
12932de962bdSlukem if ( quotedIA52strval( p, &attrValue,
12942de962bdSlukem &p, flags, ctx ) ) {
12952de962bdSlukem goto parsing_error;
12962de962bdSlukem }
12972de962bdSlukem
12982de962bdSlukem state = GOTAVA;
12992de962bdSlukem break;
13002de962bdSlukem
13012de962bdSlukem case GOTAVA: {
13022de962bdSlukem int rdnsep = 0;
13032de962bdSlukem
13042de962bdSlukem if ( !( flags & LDAP_DN_SKIP ) ) {
13052de962bdSlukem LDAPAVA *ava;
13062de962bdSlukem
13072de962bdSlukem /*
13082de962bdSlukem * we accept empty values
13092de962bdSlukem */
13102de962bdSlukem ava = ldapava_new( &attrType, &attrValue,
13112de962bdSlukem attrValueEncoding, ctx );
13122de962bdSlukem if ( ava == NULL ) {
13132de962bdSlukem rc = LDAP_NO_MEMORY;
13142de962bdSlukem goto parsing_error;
13152de962bdSlukem }
13162de962bdSlukem tmpRDN[navas++] = ava;
13172de962bdSlukem
13182de962bdSlukem attrValue.bv_val = NULL;
13192de962bdSlukem attrValue.bv_len = 0;
13202de962bdSlukem
13212de962bdSlukem /*
13222de962bdSlukem * prepare room for new AVAs if needed
13232de962bdSlukem */
13242de962bdSlukem if (navas == num_slots) {
13252de962bdSlukem LDAPAVA **tmp;
13262de962bdSlukem
13272de962bdSlukem if ( tmpRDN == tmpRDN_ ) {
13282de962bdSlukem tmp = LDAP_MALLOCX( num_slots * 2 * sizeof( LDAPAVA * ), ctx );
13292de962bdSlukem if ( tmp == NULL ) {
13302de962bdSlukem rc = LDAP_NO_MEMORY;
13312de962bdSlukem goto parsing_error;
13322de962bdSlukem }
13332de962bdSlukem AC_MEMCPY( tmp, tmpRDN, num_slots * sizeof( LDAPAVA * ) );
13342de962bdSlukem
13352de962bdSlukem } else {
13362de962bdSlukem tmp = LDAP_REALLOCX( tmpRDN, num_slots * 2 * sizeof( LDAPAVA * ), ctx );
13372de962bdSlukem if ( tmp == NULL ) {
13382de962bdSlukem rc = LDAP_NO_MEMORY;
13392de962bdSlukem goto parsing_error;
13402de962bdSlukem }
13412de962bdSlukem }
13422de962bdSlukem
13432de962bdSlukem tmpRDN = tmp;
13442de962bdSlukem num_slots *= 2;
13452de962bdSlukem }
13462de962bdSlukem }
13472de962bdSlukem
13482de962bdSlukem /*
13492de962bdSlukem * if we got an AVA separator ('+', or ',' for DCE )
13502de962bdSlukem * we expect a new AVA for this RDN; otherwise
13512de962bdSlukem * we add the RDN to the DN
13522de962bdSlukem */
13532de962bdSlukem switch ( LDAP_DN_FORMAT( flags ) ) {
13542de962bdSlukem case LDAP_DN_FORMAT_LDAP:
13552de962bdSlukem case LDAP_DN_FORMAT_LDAPV3:
13562de962bdSlukem case LDAP_DN_FORMAT_LDAPV2:
13572de962bdSlukem if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
13582de962bdSlukem rdnsep = 1;
13592de962bdSlukem }
13602de962bdSlukem break;
13612de962bdSlukem
13622de962bdSlukem case LDAP_DN_FORMAT_DCE:
13632de962bdSlukem if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
13642de962bdSlukem rdnsep = 1;
13652de962bdSlukem }
13662de962bdSlukem break;
13672de962bdSlukem }
13682de962bdSlukem
13692de962bdSlukem if ( rdnsep ) {
13702de962bdSlukem /*
13712de962bdSlukem * the RDN is over, phew
13722de962bdSlukem */
13732de962bdSlukem *n = p;
13742de962bdSlukem if ( !( flags & LDAP_DN_SKIP ) ) {
13752de962bdSlukem newRDN = (LDAPRDN)LDAP_MALLOCX(
13762de962bdSlukem sizeof(LDAPAVA) * (navas+1), ctx );
13772de962bdSlukem if ( newRDN == NULL ) {
13782de962bdSlukem rc = LDAP_NO_MEMORY;
13792de962bdSlukem goto parsing_error;
13802de962bdSlukem } else {
13812de962bdSlukem AC_MEMCPY( newRDN, tmpRDN, sizeof(LDAPAVA *) * navas);
13822de962bdSlukem newRDN[navas] = NULL;
13832de962bdSlukem }
13842de962bdSlukem
13852de962bdSlukem }
13862de962bdSlukem rc = LDAP_SUCCESS;
13872de962bdSlukem goto return_result;
13882de962bdSlukem }
13892de962bdSlukem
13902de962bdSlukem /* they should have been used in an AVA */
13912de962bdSlukem attrType.bv_val = NULL;
13922de962bdSlukem attrValue.bv_val = NULL;
13932de962bdSlukem
13942de962bdSlukem p++;
13952de962bdSlukem state = B4AVA;
13962de962bdSlukem break;
13972de962bdSlukem }
13982de962bdSlukem
13992de962bdSlukem default:
14002de962bdSlukem assert( 0 );
14012de962bdSlukem goto parsing_error;
14022de962bdSlukem }
14032de962bdSlukem }
14042de962bdSlukem *n = p;
14052de962bdSlukem
14062de962bdSlukem parsing_error:;
14072de962bdSlukem /* They are set to NULL after they're used in an AVA */
14082de962bdSlukem
14092de962bdSlukem if ( attrValue.bv_val ) {
14102de962bdSlukem LDAP_FREEX( attrValue.bv_val, ctx );
14112de962bdSlukem }
14122de962bdSlukem
14132de962bdSlukem for ( navas-- ; navas >= 0; navas-- ) {
14142de962bdSlukem ldapava_free( tmpRDN[navas], ctx );
14152de962bdSlukem }
14162de962bdSlukem
14172de962bdSlukem return_result:;
14182de962bdSlukem
14192de962bdSlukem if ( tmpRDN != tmpRDN_ ) {
14202de962bdSlukem LDAP_FREEX( tmpRDN, ctx );
14212de962bdSlukem }
14222de962bdSlukem
14232de962bdSlukem if ( rdn ) {
14242de962bdSlukem *rdn = newRDN;
14252de962bdSlukem }
14262de962bdSlukem
14272de962bdSlukem return( rc );
14282de962bdSlukem }
14292de962bdSlukem
14302de962bdSlukem /*
14312de962bdSlukem * reads in a UTF-8 string value, unescaping stuff:
14322de962bdSlukem * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
14332de962bdSlukem * '\' + HEXPAIR(p) -> unhex(p)
14342de962bdSlukem */
14352de962bdSlukem static int
str2strval(const char * str,ber_len_t stoplen,struct berval * val,const char ** next,unsigned flags,int * retFlags,void * ctx)14362de962bdSlukem str2strval( const char *str, ber_len_t stoplen, struct berval *val, const char **next, unsigned flags, int *retFlags, void *ctx )
14372de962bdSlukem {
14382de962bdSlukem const char *p, *end, *startPos, *endPos = NULL;
14392de962bdSlukem ber_len_t len, escapes;
14402de962bdSlukem
14412de962bdSlukem assert( str != NULL );
14422de962bdSlukem assert( val != NULL );
14432de962bdSlukem assert( next != NULL );
14442de962bdSlukem
14452de962bdSlukem *next = NULL;
14462de962bdSlukem end = str + stoplen;
14472de962bdSlukem for ( startPos = p = str, escapes = 0; p < end; p++ ) {
14482de962bdSlukem if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
14492de962bdSlukem p++;
14502de962bdSlukem if ( p[ 0 ] == '\0' ) {
14512de962bdSlukem return( 1 );
14522de962bdSlukem }
14532de962bdSlukem if ( LDAP_DN_MAYESCAPE( p[ 0 ] ) ) {
14542de962bdSlukem escapes++;
14552de962bdSlukem continue;
14562de962bdSlukem }
14572de962bdSlukem
14582de962bdSlukem if ( LDAP_DN_HEXPAIR( p ) ) {
14592de962bdSlukem char c;
14602de962bdSlukem
14612de962bdSlukem hexstr2bin( p, &c );
14622de962bdSlukem escapes += 2;
14632de962bdSlukem
14642de962bdSlukem if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
14652de962bdSlukem
14662de962bdSlukem /*
14672de962bdSlukem * we assume the string is UTF-8
14682de962bdSlukem */
14692de962bdSlukem *retFlags = LDAP_AVA_NONPRINTABLE;
14702de962bdSlukem }
14712de962bdSlukem p++;
14722de962bdSlukem
14732de962bdSlukem continue;
14742de962bdSlukem }
14752de962bdSlukem
14762de962bdSlukem if ( LDAP_DN_PEDANTIC & flags ) {
14772de962bdSlukem return( 1 );
14782de962bdSlukem }
14792de962bdSlukem /*
14802de962bdSlukem * we do not allow escaping
14812de962bdSlukem * of chars that don't need
14822de962bdSlukem * to and do not belong to
14832de962bdSlukem * HEXDIGITS
14842de962bdSlukem */
14852de962bdSlukem return( 1 );
14862de962bdSlukem
14872de962bdSlukem } else if ( !LDAP_DN_ASCII_PRINTABLE( p[ 0 ] ) ) {
14882de962bdSlukem if ( p[ 0 ] == '\0' ) {
14892de962bdSlukem return( 1 );
14902de962bdSlukem }
14912de962bdSlukem *retFlags = LDAP_AVA_NONPRINTABLE;
14922de962bdSlukem
14932de962bdSlukem } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) )
14942de962bdSlukem || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
14952de962bdSlukem break;
14962de962bdSlukem
14972de962bdSlukem } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
14982de962bdSlukem /*
14992de962bdSlukem * FIXME: maybe we can add
15002de962bdSlukem * escapes if not pedantic?
15012de962bdSlukem */
15022de962bdSlukem return( 1 );
15032de962bdSlukem }
15042de962bdSlukem }
15052de962bdSlukem
15062de962bdSlukem /*
15072de962bdSlukem * we do allow unescaped spaces at the end
15082de962bdSlukem * of the value only in non-pedantic mode
15092de962bdSlukem */
15102de962bdSlukem if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
15112de962bdSlukem !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
15122de962bdSlukem if ( flags & LDAP_DN_PEDANTIC ) {
15132de962bdSlukem return( 1 );
15142de962bdSlukem }
15152de962bdSlukem
15162de962bdSlukem /* strip trailing (unescaped) spaces */
15172de962bdSlukem for ( endPos = p - 1;
15182de962bdSlukem endPos > startPos + 1 &&
15192de962bdSlukem LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
15202de962bdSlukem !LDAP_DN_ESCAPE( endPos[ -2 ] );
15212de962bdSlukem endPos-- ) {
15222de962bdSlukem /* no op */
15232de962bdSlukem }
15242de962bdSlukem }
15252de962bdSlukem
15262de962bdSlukem *next = p;
15272de962bdSlukem if ( flags & LDAP_DN_SKIP ) {
15282de962bdSlukem return( 0 );
15292de962bdSlukem }
15302de962bdSlukem
15312de962bdSlukem /*
15322de962bdSlukem * FIXME: test memory?
15332de962bdSlukem */
15342de962bdSlukem len = ( endPos ? endPos : p ) - startPos - escapes;
15352de962bdSlukem val->bv_len = len;
15362de962bdSlukem
15372de962bdSlukem if ( escapes == 0 ) {
15382de962bdSlukem if ( *retFlags & LDAP_AVA_NONPRINTABLE ) {
15392de962bdSlukem val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1540*549b59edSchristos if ( val->bv_val == NULL ) {
1541*549b59edSchristos return( 1 );
1542*549b59edSchristos }
1543*549b59edSchristos
15442de962bdSlukem AC_MEMCPY( val->bv_val, startPos, len );
15452de962bdSlukem val->bv_val[ len ] = '\0';
15462de962bdSlukem } else {
15472de962bdSlukem val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
15482de962bdSlukem }
15492de962bdSlukem
15502de962bdSlukem } else {
15512de962bdSlukem ber_len_t s, d;
15522de962bdSlukem
15532de962bdSlukem val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1554*549b59edSchristos if ( val->bv_val == NULL ) {
1555*549b59edSchristos return( 1 );
1556*549b59edSchristos }
1557*549b59edSchristos
15582de962bdSlukem for ( s = 0, d = 0; d < len; ) {
15592de962bdSlukem if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
15602de962bdSlukem s++;
15612de962bdSlukem if ( LDAP_DN_MAYESCAPE( startPos[ s ] ) ) {
15622de962bdSlukem val->bv_val[ d++ ] =
15632de962bdSlukem startPos[ s++ ];
15642de962bdSlukem
15652de962bdSlukem } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
15662de962bdSlukem char c;
15672de962bdSlukem
15682de962bdSlukem hexstr2bin( &startPos[ s ], &c );
15692de962bdSlukem val->bv_val[ d++ ] = c;
15702de962bdSlukem s += 2;
15712de962bdSlukem
15722de962bdSlukem } else {
15732de962bdSlukem /* we should never get here */
15742de962bdSlukem assert( 0 );
15752de962bdSlukem }
15762de962bdSlukem
15772de962bdSlukem } else {
15782de962bdSlukem val->bv_val[ d++ ] = startPos[ s++ ];
15792de962bdSlukem }
15802de962bdSlukem }
15812de962bdSlukem
15822de962bdSlukem val->bv_val[ d ] = '\0';
15832de962bdSlukem assert( d == len );
15842de962bdSlukem }
15852de962bdSlukem
15862de962bdSlukem return( 0 );
15872de962bdSlukem }
15882de962bdSlukem
15892de962bdSlukem static int
DCE2strval(const char * str,struct berval * val,const char ** next,unsigned flags,void * ctx)15902de962bdSlukem DCE2strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
15912de962bdSlukem {
15922de962bdSlukem const char *p, *startPos, *endPos = NULL;
15932de962bdSlukem ber_len_t len, escapes;
15942de962bdSlukem
15952de962bdSlukem assert( str != NULL );
15962de962bdSlukem assert( val != NULL );
15972de962bdSlukem assert( next != NULL );
15982de962bdSlukem
15992de962bdSlukem *next = NULL;
16002de962bdSlukem
16012de962bdSlukem for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
16022de962bdSlukem if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
16032de962bdSlukem p++;
16042de962bdSlukem if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
16052de962bdSlukem escapes++;
16062de962bdSlukem
16072de962bdSlukem } else {
16082de962bdSlukem return( 1 );
16092de962bdSlukem }
16102de962bdSlukem
16112de962bdSlukem } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
16122de962bdSlukem break;
16132de962bdSlukem }
16142de962bdSlukem
16152de962bdSlukem /*
16162de962bdSlukem * FIXME: can we accept anything else? I guess we need
16172de962bdSlukem * to stop if a value is not legal
16182de962bdSlukem */
16192de962bdSlukem }
16202de962bdSlukem
16212de962bdSlukem /*
16222de962bdSlukem * (unescaped) trailing spaces are trimmed must be silently ignored;
16232de962bdSlukem * so we eat them
16242de962bdSlukem */
16252de962bdSlukem if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
16262de962bdSlukem !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
16272de962bdSlukem if ( flags & LDAP_DN_PEDANTIC ) {
16282de962bdSlukem return( 1 );
16292de962bdSlukem }
16302de962bdSlukem
16312de962bdSlukem /* strip trailing (unescaped) spaces */
16322de962bdSlukem for ( endPos = p - 1;
16332de962bdSlukem endPos > startPos + 1 &&
16342de962bdSlukem LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
16352de962bdSlukem !LDAP_DN_ESCAPE( endPos[ -2 ] );
16362de962bdSlukem endPos-- ) {
16372de962bdSlukem /* no op */
16382de962bdSlukem }
16392de962bdSlukem }
16402de962bdSlukem
16412de962bdSlukem *next = p;
16422de962bdSlukem if ( flags & LDAP_DN_SKIP ) {
16432de962bdSlukem return( 0 );
16442de962bdSlukem }
16452de962bdSlukem
16462de962bdSlukem len = ( endPos ? endPos : p ) - startPos - escapes;
16472de962bdSlukem val->bv_len = len;
16482de962bdSlukem if ( escapes == 0 ){
16492de962bdSlukem val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
16502de962bdSlukem
16512de962bdSlukem } else {
16522de962bdSlukem ber_len_t s, d;
16532de962bdSlukem
16542de962bdSlukem val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1655*549b59edSchristos if ( val->bv_val == NULL ) {
1656*549b59edSchristos return( 1 );
1657*549b59edSchristos }
1658*549b59edSchristos
16592de962bdSlukem for ( s = 0, d = 0; d < len; ) {
16602de962bdSlukem /*
16612de962bdSlukem * This point is reached only if escapes
16622de962bdSlukem * are properly used, so all we need to
16632de962bdSlukem * do is eat them
16642de962bdSlukem */
16652de962bdSlukem if ( LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
16662de962bdSlukem s++;
16672de962bdSlukem
16682de962bdSlukem }
16692de962bdSlukem val->bv_val[ d++ ] = startPos[ s++ ];
16702de962bdSlukem }
16712de962bdSlukem val->bv_val[ d ] = '\0';
16722de962bdSlukem assert( strlen( val->bv_val ) == len );
16732de962bdSlukem }
16742de962bdSlukem
16752de962bdSlukem return( 0 );
16762de962bdSlukem }
16772de962bdSlukem
16782de962bdSlukem static int
IA52strval(const char * str,struct berval * val,const char ** next,unsigned flags,void * ctx)16792de962bdSlukem IA52strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
16802de962bdSlukem {
16812de962bdSlukem const char *p, *startPos, *endPos = NULL;
16822de962bdSlukem ber_len_t len, escapes;
16832de962bdSlukem
16842de962bdSlukem assert( str != NULL );
16852de962bdSlukem assert( val != NULL );
16862de962bdSlukem assert( next != NULL );
16872de962bdSlukem
16882de962bdSlukem *next = NULL;
16892de962bdSlukem
16902de962bdSlukem /*
16912de962bdSlukem * LDAPv2 (RFC 1779)
16922de962bdSlukem */
16932de962bdSlukem
16942de962bdSlukem for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
16952de962bdSlukem if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
16962de962bdSlukem p++;
16972de962bdSlukem if ( p[ 0 ] == '\0' ) {
16982de962bdSlukem return( 1 );
16992de962bdSlukem }
17002de962bdSlukem
17012de962bdSlukem if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
17022de962bdSlukem && ( LDAP_DN_PEDANTIC & flags ) ) {
17032de962bdSlukem return( 1 );
17042de962bdSlukem }
17052de962bdSlukem escapes++;
17062de962bdSlukem
17072de962bdSlukem } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
17082de962bdSlukem break;
17092de962bdSlukem }
17102de962bdSlukem
17112de962bdSlukem /*
17122de962bdSlukem * FIXME: can we accept anything else? I guess we need
17132de962bdSlukem * to stop if a value is not legal
17142de962bdSlukem */
17152de962bdSlukem }
17162de962bdSlukem
17172de962bdSlukem /* strip trailing (unescaped) spaces */
17182de962bdSlukem for ( endPos = p;
17192de962bdSlukem endPos > startPos + 1 &&
17202de962bdSlukem LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
17212de962bdSlukem !LDAP_DN_ESCAPE( endPos[ -2 ] );
17222de962bdSlukem endPos-- ) {
17232de962bdSlukem /* no op */
17242de962bdSlukem }
17252de962bdSlukem
17262de962bdSlukem *next = p;
17272de962bdSlukem if ( flags & LDAP_DN_SKIP ) {
17282de962bdSlukem return( 0 );
17292de962bdSlukem }
17302de962bdSlukem
17312de962bdSlukem len = ( endPos ? endPos : p ) - startPos - escapes;
17322de962bdSlukem val->bv_len = len;
17332de962bdSlukem if ( escapes == 0 ) {
17342de962bdSlukem val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
17352de962bdSlukem
17362de962bdSlukem } else {
17372de962bdSlukem ber_len_t s, d;
17382de962bdSlukem
17392de962bdSlukem val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1740*549b59edSchristos if ( val->bv_val == NULL ) {
1741*549b59edSchristos return( 1 );
1742*549b59edSchristos }
1743*549b59edSchristos
17442de962bdSlukem for ( s = 0, d = 0; d < len; ) {
17452de962bdSlukem if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
17462de962bdSlukem s++;
17472de962bdSlukem }
17482de962bdSlukem val->bv_val[ d++ ] = startPos[ s++ ];
17492de962bdSlukem }
17502de962bdSlukem val->bv_val[ d ] = '\0';
17512de962bdSlukem assert( strlen( val->bv_val ) == len );
17522de962bdSlukem }
17532de962bdSlukem
17542de962bdSlukem return( 0 );
17552de962bdSlukem }
17562de962bdSlukem
17572de962bdSlukem static int
quotedIA52strval(const char * str,struct berval * val,const char ** next,unsigned flags,void * ctx)17582de962bdSlukem quotedIA52strval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
17592de962bdSlukem {
17602de962bdSlukem const char *p, *startPos, *endPos = NULL;
17612de962bdSlukem ber_len_t len;
17622de962bdSlukem unsigned escapes = 0;
17632de962bdSlukem
17642de962bdSlukem assert( str != NULL );
17652de962bdSlukem assert( val != NULL );
17662de962bdSlukem assert( next != NULL );
17672de962bdSlukem
17682de962bdSlukem *next = NULL;
17692de962bdSlukem
17702de962bdSlukem /* initial quote already eaten */
17712de962bdSlukem for ( startPos = p = str; p[ 0 ]; p++ ) {
17722de962bdSlukem /*
17732de962bdSlukem * According to RFC 1779, the quoted value can
17742de962bdSlukem * contain escaped as well as unescaped special values;
17752de962bdSlukem * as a consequence we tolerate escaped values
17762de962bdSlukem * (e.g. '"\,"' -> '\,') and escape unescaped specials
17772de962bdSlukem * (e.g. '","' -> '\,').
17782de962bdSlukem */
17792de962bdSlukem if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
17802de962bdSlukem if ( p[ 1 ] == '\0' ) {
17812de962bdSlukem return( 1 );
17822de962bdSlukem }
17832de962bdSlukem p++;
17842de962bdSlukem
17852de962bdSlukem if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
17862de962bdSlukem && ( LDAP_DN_PEDANTIC & flags ) ) {
17872de962bdSlukem /*
17882de962bdSlukem * do we allow to escape normal chars?
17892de962bdSlukem * LDAPv2 does not allow any mechanism
17902de962bdSlukem * for escaping chars with '\' and hex
17912de962bdSlukem * pair
17922de962bdSlukem */
17932de962bdSlukem return( 1 );
17942de962bdSlukem }
17952de962bdSlukem escapes++;
17962de962bdSlukem
17972de962bdSlukem } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
17982de962bdSlukem endPos = p;
17992de962bdSlukem /* eat closing quotes */
18002de962bdSlukem p++;
18012de962bdSlukem break;
18022de962bdSlukem }
18032de962bdSlukem
18042de962bdSlukem /*
18052de962bdSlukem * FIXME: can we accept anything else? I guess we need
18062de962bdSlukem * to stop if a value is not legal
18072de962bdSlukem */
18082de962bdSlukem }
18092de962bdSlukem
18102de962bdSlukem if ( endPos == NULL ) {
18112de962bdSlukem return( 1 );
18122de962bdSlukem }
18132de962bdSlukem
18142de962bdSlukem /* Strip trailing (unescaped) spaces */
18152de962bdSlukem for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
18162de962bdSlukem /* no op */
18172de962bdSlukem }
18182de962bdSlukem
18192de962bdSlukem *next = p;
18202de962bdSlukem if ( flags & LDAP_DN_SKIP ) {
18212de962bdSlukem return( 0 );
18222de962bdSlukem }
18232de962bdSlukem
18242de962bdSlukem len = endPos - startPos - escapes;
18252de962bdSlukem assert( endPos >= startPos + escapes );
18262de962bdSlukem val->bv_len = len;
18272de962bdSlukem if ( escapes == 0 ) {
18282de962bdSlukem val->bv_val = LDAP_STRNDUPX( startPos, len, ctx );
18292de962bdSlukem
18302de962bdSlukem } else {
18312de962bdSlukem ber_len_t s, d;
18322de962bdSlukem
18332de962bdSlukem val->bv_val = LDAP_MALLOCX( len + 1, ctx );
1834*549b59edSchristos if ( val->bv_val == NULL ) {
1835*549b59edSchristos return( 1 );
1836*549b59edSchristos }
1837*549b59edSchristos
18382de962bdSlukem val->bv_len = len;
18392de962bdSlukem
18402de962bdSlukem for ( s = d = 0; d < len; ) {
18412de962bdSlukem if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
18422de962bdSlukem s++;
18432de962bdSlukem }
18442de962bdSlukem val->bv_val[ d++ ] = str[ s++ ];
18452de962bdSlukem }
18462de962bdSlukem val->bv_val[ d ] = '\0';
18472de962bdSlukem assert( strlen( val->bv_val ) == len );
18482de962bdSlukem }
18492de962bdSlukem
18502de962bdSlukem return( 0 );
18512de962bdSlukem }
18522de962bdSlukem
18532de962bdSlukem static int
hexstr2bin(const char * str,char * c)18542de962bdSlukem hexstr2bin( const char *str, char *c )
18552de962bdSlukem {
18562de962bdSlukem char c1, c2;
18572de962bdSlukem
18582de962bdSlukem assert( str != NULL );
18592de962bdSlukem assert( c != NULL );
18602de962bdSlukem
18612de962bdSlukem c1 = str[ 0 ];
18622de962bdSlukem c2 = str[ 1 ];
18632de962bdSlukem
18642de962bdSlukem if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
18652de962bdSlukem *c = c1 - '0';
18662de962bdSlukem
18672de962bdSlukem } else {
18682de962bdSlukem if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c1 ) ) {
18692de962bdSlukem *c = c1 - 'A' + 10;
18702de962bdSlukem } else {
18712de962bdSlukem assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) );
18722de962bdSlukem *c = c1 - 'a' + 10;
18732de962bdSlukem }
18742de962bdSlukem }
18752de962bdSlukem
18762de962bdSlukem *c <<= 4;
18772de962bdSlukem
18782de962bdSlukem if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
18792de962bdSlukem *c += c2 - '0';
18802de962bdSlukem
18812de962bdSlukem } else {
18822de962bdSlukem if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c2 ) ) {
18832de962bdSlukem *c += c2 - 'A' + 10;
18842de962bdSlukem } else {
18852de962bdSlukem assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) );
18862de962bdSlukem *c += c2 - 'a' + 10;
18872de962bdSlukem }
18882de962bdSlukem }
18892de962bdSlukem
18902de962bdSlukem return( 0 );
18912de962bdSlukem }
18922de962bdSlukem
18932de962bdSlukem static int
hexstr2binval(const char * str,struct berval * val,const char ** next,unsigned flags,void * ctx)18942de962bdSlukem hexstr2binval( const char *str, struct berval *val, const char **next, unsigned flags, void *ctx )
18952de962bdSlukem {
18962de962bdSlukem const char *p, *startPos, *endPos = NULL;
18972de962bdSlukem ber_len_t len;
18982de962bdSlukem ber_len_t s, d;
18992de962bdSlukem
19002de962bdSlukem assert( str != NULL );
19012de962bdSlukem assert( val != NULL );
19022de962bdSlukem assert( next != NULL );
19032de962bdSlukem
19042de962bdSlukem *next = NULL;
19052de962bdSlukem
19062de962bdSlukem for ( startPos = p = str; p[ 0 ]; p += 2 ) {
19072de962bdSlukem switch ( LDAP_DN_FORMAT( flags ) ) {
19082de962bdSlukem case LDAP_DN_FORMAT_LDAPV3:
19092de962bdSlukem if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
19102de962bdSlukem goto end_of_value;
19112de962bdSlukem }
19122de962bdSlukem break;
19132de962bdSlukem
19142de962bdSlukem case LDAP_DN_FORMAT_LDAP:
19152de962bdSlukem case LDAP_DN_FORMAT_LDAPV2:
19162de962bdSlukem if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
19172de962bdSlukem goto end_of_value;
19182de962bdSlukem }
19192de962bdSlukem break;
19202de962bdSlukem
19212de962bdSlukem case LDAP_DN_FORMAT_DCE:
19222de962bdSlukem if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
19232de962bdSlukem goto end_of_value;
19242de962bdSlukem }
19252de962bdSlukem break;
19262de962bdSlukem }
19272de962bdSlukem
19282de962bdSlukem if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
19292de962bdSlukem if ( flags & LDAP_DN_PEDANTIC ) {
19302de962bdSlukem return( 1 );
19312de962bdSlukem }
19322de962bdSlukem endPos = p;
19332de962bdSlukem
19342de962bdSlukem for ( ; p[ 0 ]; p++ ) {
19352de962bdSlukem switch ( LDAP_DN_FORMAT( flags ) ) {
19362de962bdSlukem case LDAP_DN_FORMAT_LDAPV3:
19372de962bdSlukem if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
19382de962bdSlukem goto end_of_value;
19392de962bdSlukem }
19402de962bdSlukem break;
19412de962bdSlukem
19422de962bdSlukem case LDAP_DN_FORMAT_LDAP:
19432de962bdSlukem case LDAP_DN_FORMAT_LDAPV2:
19442de962bdSlukem if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
19452de962bdSlukem goto end_of_value;
19462de962bdSlukem }
19472de962bdSlukem break;
19482de962bdSlukem
19492de962bdSlukem case LDAP_DN_FORMAT_DCE:
19502de962bdSlukem if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
19512de962bdSlukem goto end_of_value;
19522de962bdSlukem }
19532de962bdSlukem break;
19542de962bdSlukem }
19552de962bdSlukem }
19562de962bdSlukem break;
19572de962bdSlukem }
19582de962bdSlukem
19592de962bdSlukem if ( !LDAP_DN_HEXPAIR( p ) ) {
19602de962bdSlukem return( 1 );
19612de962bdSlukem }
19622de962bdSlukem }
19632de962bdSlukem
19642de962bdSlukem end_of_value:;
19652de962bdSlukem
19662de962bdSlukem *next = p;
19672de962bdSlukem if ( flags & LDAP_DN_SKIP ) {
19682de962bdSlukem return( 0 );
19692de962bdSlukem }
19702de962bdSlukem
19712de962bdSlukem len = ( ( endPos ? endPos : p ) - startPos ) / 2;
19722de962bdSlukem /* must be even! */
19732de962bdSlukem assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
19742de962bdSlukem
19752de962bdSlukem val->bv_len = len;
19762de962bdSlukem val->bv_val = LDAP_MALLOCX( len + 1, ctx );
19772de962bdSlukem if ( val->bv_val == NULL ) {
19782de962bdSlukem return( LDAP_NO_MEMORY );
19792de962bdSlukem }
19802de962bdSlukem
19812de962bdSlukem for ( s = 0, d = 0; d < len; s += 2, d++ ) {
19822de962bdSlukem char c;
19832de962bdSlukem
19842de962bdSlukem hexstr2bin( &startPos[ s ], &c );
19852de962bdSlukem
19862de962bdSlukem val->bv_val[ d ] = c;
19872de962bdSlukem }
19882de962bdSlukem
19892de962bdSlukem val->bv_val[ d ] = '\0';
19902de962bdSlukem
19912de962bdSlukem return( 0 );
19922de962bdSlukem }
19932de962bdSlukem
19942de962bdSlukem /*
19952de962bdSlukem * convert a byte in a hexadecimal pair
19962de962bdSlukem */
19972de962bdSlukem static int
byte2hexpair(const char * val,char * pair)19982de962bdSlukem byte2hexpair( const char *val, char *pair )
19992de962bdSlukem {
20002de962bdSlukem static const char hexdig[] = "0123456789ABCDEF";
20012de962bdSlukem
20022de962bdSlukem assert( val != NULL );
20032de962bdSlukem assert( pair != NULL );
20042de962bdSlukem
20052de962bdSlukem /*
20062de962bdSlukem * we assume the string has enough room for the hex encoding
20072de962bdSlukem * of the value
20082de962bdSlukem */
20092de962bdSlukem
20102de962bdSlukem pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
20112de962bdSlukem pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
20122de962bdSlukem
20132de962bdSlukem return( 0 );
20142de962bdSlukem }
20152de962bdSlukem
20162de962bdSlukem /*
20172de962bdSlukem * convert a binary value in hexadecimal pairs
20182de962bdSlukem */
20192de962bdSlukem static int
binval2hexstr(struct berval * val,char * str)20202de962bdSlukem binval2hexstr( struct berval *val, char *str )
20212de962bdSlukem {
20222de962bdSlukem ber_len_t s, d;
20232de962bdSlukem
20242de962bdSlukem assert( val != NULL );
20252de962bdSlukem assert( str != NULL );
20262de962bdSlukem
20272de962bdSlukem if ( val->bv_len == 0 ) {
20282de962bdSlukem return( 0 );
20292de962bdSlukem }
20302de962bdSlukem
20312de962bdSlukem /*
20322de962bdSlukem * we assume the string has enough room for the hex encoding
20332de962bdSlukem * of the value
20342de962bdSlukem */
20352de962bdSlukem
20362de962bdSlukem for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
20372de962bdSlukem byte2hexpair( &val->bv_val[ s ], &str[ d ] );
20382de962bdSlukem }
20392de962bdSlukem
20402de962bdSlukem return( 0 );
20412de962bdSlukem }
20422de962bdSlukem
20432de962bdSlukem /*
20442de962bdSlukem * Length of the string representation, accounting for escaped hex
20452de962bdSlukem * of UTF-8 chars
20462de962bdSlukem */
20472de962bdSlukem static int
strval2strlen(struct berval * val,unsigned flags,ber_len_t * len)20482de962bdSlukem strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
20492de962bdSlukem {
20502de962bdSlukem ber_len_t l, cl = 1;
20512de962bdSlukem char *p, *end;
20522de962bdSlukem int escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3;
20532de962bdSlukem #ifdef PRETTY_ESCAPE
20542de962bdSlukem int escaped_ascii_len = LDAP_DN_IS_PRETTY( flags ) ? 2 : 3;
20552de962bdSlukem #endif /* PRETTY_ESCAPE */
20562de962bdSlukem
20572de962bdSlukem assert( val != NULL );
20582de962bdSlukem assert( len != NULL );
20592de962bdSlukem
20602de962bdSlukem *len = 0;
20612de962bdSlukem if ( val->bv_len == 0 ) {
20622de962bdSlukem return( 0 );
20632de962bdSlukem }
20642de962bdSlukem
20652de962bdSlukem end = val->bv_val + val->bv_len - 1;
20662de962bdSlukem for ( l = 0, p = val->bv_val; p <= end; p += cl ) {
20672de962bdSlukem
20682de962bdSlukem /*
20692de962bdSlukem * escape '%x00'
20702de962bdSlukem */
20712de962bdSlukem if ( p[ 0 ] == '\0' ) {
20722de962bdSlukem cl = 1;
20732de962bdSlukem l += 3;
20742de962bdSlukem continue;
20752de962bdSlukem }
20762de962bdSlukem
20772de962bdSlukem cl = LDAP_UTF8_CHARLEN2( p, cl );
20782de962bdSlukem if ( cl == 0 ) {
20792de962bdSlukem /* illegal utf-8 char! */
20802de962bdSlukem return( -1 );
20812de962bdSlukem
20822de962bdSlukem } else if ( cl > 1 ) {
20832de962bdSlukem ber_len_t cnt;
20842de962bdSlukem
20852de962bdSlukem for ( cnt = 1; cnt < cl; cnt++ ) {
20862de962bdSlukem if ( ( p[ cnt ] & 0xc0 ) != 0x80 ) {
20872de962bdSlukem return( -1 );
20882de962bdSlukem }
20892de962bdSlukem }
20902de962bdSlukem l += escaped_byte_len * cl;
20912de962bdSlukem
20922de962bdSlukem } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
20932de962bdSlukem || LDAP_DN_SHOULDESCAPE( p[ 0 ] )
20942de962bdSlukem || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
20952de962bdSlukem || ( p == end && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
20962de962bdSlukem #ifdef PRETTY_ESCAPE
20972de962bdSlukem #if 0
20982de962bdSlukem if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) {
20992de962bdSlukem #else
21002de962bdSlukem if ( LDAP_DN_WILLESCAPE_CHAR( p[ 0 ] ) ) {
21012de962bdSlukem #endif
21022de962bdSlukem
21032de962bdSlukem /*
21042de962bdSlukem * there might be some chars we want
21052de962bdSlukem * to escape in form of a couple
21062de962bdSlukem * of hexdigits for optimization purposes
21072de962bdSlukem */
21082de962bdSlukem l += 3;
21092de962bdSlukem
21102de962bdSlukem } else {
21112de962bdSlukem l += escaped_ascii_len;
21122de962bdSlukem }
21132de962bdSlukem #else /* ! PRETTY_ESCAPE */
21142de962bdSlukem l += 3;
21152de962bdSlukem #endif /* ! PRETTY_ESCAPE */
21162de962bdSlukem
21172de962bdSlukem } else {
21182de962bdSlukem l++;
21192de962bdSlukem }
21202de962bdSlukem }
21212de962bdSlukem
21222de962bdSlukem *len = l;
21232de962bdSlukem
21242de962bdSlukem return( 0 );
21252de962bdSlukem }
21262de962bdSlukem
21272de962bdSlukem /*
21282de962bdSlukem * convert to string representation, escaping with hex the UTF-8 stuff;
21292de962bdSlukem * assume the destination has enough room for escaping
21302de962bdSlukem */
21312de962bdSlukem static int
21322de962bdSlukem strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
21332de962bdSlukem {
21342de962bdSlukem ber_len_t s, d, end;
21352de962bdSlukem
21362de962bdSlukem assert( val != NULL );
21372de962bdSlukem assert( str != NULL );
21382de962bdSlukem assert( len != NULL );
21392de962bdSlukem
21402de962bdSlukem if ( val->bv_len == 0 ) {
21412de962bdSlukem *len = 0;
21422de962bdSlukem return( 0 );
21432de962bdSlukem }
21442de962bdSlukem
21452de962bdSlukem /*
21462de962bdSlukem * we assume the string has enough room for the hex encoding
21472de962bdSlukem * of the value
21482de962bdSlukem */
21492de962bdSlukem for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
21502de962bdSlukem ber_len_t cl;
21512de962bdSlukem
21522de962bdSlukem /*
21532de962bdSlukem * escape '%x00'
21542de962bdSlukem */
21552de962bdSlukem if ( val->bv_val[ s ] == '\0' ) {
21562de962bdSlukem cl = 1;
21572de962bdSlukem str[ d++ ] = '\\';
21582de962bdSlukem str[ d++ ] = '0';
21592de962bdSlukem str[ d++ ] = '0';
21602de962bdSlukem s++;
21612de962bdSlukem continue;
21622de962bdSlukem }
21632de962bdSlukem
21642de962bdSlukem /*
21652de962bdSlukem * The length was checked in strval2strlen();
21662de962bdSlukem */
21674e6df137Slukem cl = LDAP_UTF8_CHARLEN( &val->bv_val[ s ] );
21682de962bdSlukem
21692de962bdSlukem /*
21702de962bdSlukem * there might be some chars we want to escape in form
21712de962bdSlukem * of a couple of hexdigits for optimization purposes
21722de962bdSlukem */
21732de962bdSlukem if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) )
21742de962bdSlukem #ifdef PRETTY_ESCAPE
21752de962bdSlukem #if 0
21762de962bdSlukem || LDAP_DN_WILLESCAPE_HEX( flags, val->bv_val[ s ] )
21772de962bdSlukem #else
21782de962bdSlukem || LDAP_DN_WILLESCAPE_CHAR( val->bv_val[ s ] )
21792de962bdSlukem #endif
21802de962bdSlukem #else /* ! PRETTY_ESCAPE */
21812de962bdSlukem || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
21822de962bdSlukem || LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] )
21832de962bdSlukem || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
21842de962bdSlukem || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
21852de962bdSlukem
21862de962bdSlukem #endif /* ! PRETTY_ESCAPE */
21872de962bdSlukem ) {
21882de962bdSlukem for ( ; cl--; ) {
21892de962bdSlukem str[ d++ ] = '\\';
21902de962bdSlukem byte2hexpair( &val->bv_val[ s ], &str[ d ] );
21912de962bdSlukem s++;
21922de962bdSlukem d += 2;
21932de962bdSlukem }
21942de962bdSlukem
21952de962bdSlukem } else if ( cl > 1 ) {
21962de962bdSlukem for ( ; cl--; ) {
21972de962bdSlukem str[ d++ ] = val->bv_val[ s++ ];
21982de962bdSlukem }
21992de962bdSlukem
22002de962bdSlukem } else {
22012de962bdSlukem #ifdef PRETTY_ESCAPE
22022de962bdSlukem if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
22032de962bdSlukem || LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] )
22042de962bdSlukem || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
22052de962bdSlukem || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
22062de962bdSlukem str[ d++ ] = '\\';
22072de962bdSlukem if ( !LDAP_DN_IS_PRETTY( flags ) ) {
22082de962bdSlukem byte2hexpair( &val->bv_val[ s ], &str[ d ] );
22092de962bdSlukem s++;
22102de962bdSlukem d += 2;
22112de962bdSlukem continue;
22122de962bdSlukem }
22132de962bdSlukem }
22142de962bdSlukem #endif /* PRETTY_ESCAPE */
22152de962bdSlukem str[ d++ ] = val->bv_val[ s++ ];
22162de962bdSlukem }
22172de962bdSlukem }
22182de962bdSlukem
22192de962bdSlukem *len = d;
22202de962bdSlukem
22212de962bdSlukem return( 0 );
22222de962bdSlukem }
22232de962bdSlukem
22242de962bdSlukem /*
22252de962bdSlukem * Length of the IA5 string representation (no UTF-8 allowed)
22262de962bdSlukem */
22272de962bdSlukem static int
22282de962bdSlukem strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
22292de962bdSlukem {
22302de962bdSlukem ber_len_t l;
22312de962bdSlukem char *p;
22322de962bdSlukem
22332de962bdSlukem assert( val != NULL );
22342de962bdSlukem assert( len != NULL );
22352de962bdSlukem
22362de962bdSlukem *len = 0;
22372de962bdSlukem if ( val->bv_len == 0 ) {
22382de962bdSlukem return( 0 );
22392de962bdSlukem }
22402de962bdSlukem
22412de962bdSlukem if ( flags & LDAP_AVA_NONPRINTABLE ) {
22422de962bdSlukem /*
22432de962bdSlukem * Turn value into a binary encoded BER
22442de962bdSlukem */
22452de962bdSlukem return( -1 );
22462de962bdSlukem
22472de962bdSlukem } else {
22482de962bdSlukem for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
22492de962bdSlukem if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
22502de962bdSlukem || LDAP_DN_SHOULDESCAPE( p[ 0 ] )
22512de962bdSlukem || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
22522de962bdSlukem || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
22532de962bdSlukem l += 2;
22542de962bdSlukem
22552de962bdSlukem } else {
22562de962bdSlukem l++;
22572de962bdSlukem }
22582de962bdSlukem }
22592de962bdSlukem }
22602de962bdSlukem
22612de962bdSlukem *len = l;
22622de962bdSlukem
22632de962bdSlukem return( 0 );
22642de962bdSlukem }
22652de962bdSlukem
22662de962bdSlukem /*
22672de962bdSlukem * convert to string representation (np UTF-8)
22682de962bdSlukem * assume the destination has enough room for escaping
22692de962bdSlukem */
22702de962bdSlukem static int
22712de962bdSlukem strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
22722de962bdSlukem {
22732de962bdSlukem ber_len_t s, d, end;
22742de962bdSlukem
22752de962bdSlukem assert( val != NULL );
22762de962bdSlukem assert( str != NULL );
22772de962bdSlukem assert( len != NULL );
22782de962bdSlukem
22792de962bdSlukem if ( val->bv_len == 0 ) {
22802de962bdSlukem *len = 0;
22812de962bdSlukem return( 0 );
22822de962bdSlukem }
22832de962bdSlukem
22842de962bdSlukem if ( flags & LDAP_AVA_NONPRINTABLE ) {
22852de962bdSlukem /*
22862de962bdSlukem * Turn value into a binary encoded BER
22872de962bdSlukem */
22882de962bdSlukem *len = 0;
22892de962bdSlukem return( -1 );
22902de962bdSlukem
22912de962bdSlukem } else {
22922de962bdSlukem /*
22932de962bdSlukem * we assume the string has enough room for the hex encoding
22942de962bdSlukem * of the value
22952de962bdSlukem */
22962de962bdSlukem
22972de962bdSlukem for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
22982de962bdSlukem if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
22992de962bdSlukem || LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] )
23002de962bdSlukem || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
23012de962bdSlukem || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
23022de962bdSlukem str[ d++ ] = '\\';
23032de962bdSlukem }
23042de962bdSlukem str[ d++ ] = val->bv_val[ s++ ];
23052de962bdSlukem }
23062de962bdSlukem }
23072de962bdSlukem
23082de962bdSlukem *len = d;
23092de962bdSlukem
23102de962bdSlukem return( 0 );
23112de962bdSlukem }
23122de962bdSlukem
23132de962bdSlukem /*
23142de962bdSlukem * Length of the (supposedly) DCE string representation,
23152de962bdSlukem * accounting for escaped hex of UTF-8 chars
23162de962bdSlukem */
23172de962bdSlukem static int
23182de962bdSlukem strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
23192de962bdSlukem {
23202de962bdSlukem ber_len_t l;
23212de962bdSlukem char *p;
23222de962bdSlukem
23232de962bdSlukem assert( val != NULL );
23242de962bdSlukem assert( len != NULL );
23252de962bdSlukem
23262de962bdSlukem *len = 0;
23272de962bdSlukem if ( val->bv_len == 0 ) {
23282de962bdSlukem return( 0 );
23292de962bdSlukem }
23302de962bdSlukem
23312de962bdSlukem if ( flags & LDAP_AVA_NONPRINTABLE ) {
23322de962bdSlukem /*
23332de962bdSlukem * FIXME: Turn the value into a binary encoded BER?
23342de962bdSlukem */
23352de962bdSlukem return( -1 );
23362de962bdSlukem
23372de962bdSlukem } else {
23382de962bdSlukem for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
23392de962bdSlukem if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
23402de962bdSlukem l += 2;
23412de962bdSlukem
23422de962bdSlukem } else {
23432de962bdSlukem l++;
23442de962bdSlukem }
23452de962bdSlukem }
23462de962bdSlukem }
23472de962bdSlukem
23482de962bdSlukem *len = l;
23492de962bdSlukem
23502de962bdSlukem return( 0 );
23512de962bdSlukem }
23522de962bdSlukem
23532de962bdSlukem /*
23542de962bdSlukem * convert to (supposedly) DCE string representation,
23552de962bdSlukem * escaping with hex the UTF-8 stuff;
23562de962bdSlukem * assume the destination has enough room for escaping
23572de962bdSlukem */
23582de962bdSlukem static int
23592de962bdSlukem strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
23602de962bdSlukem {
23612de962bdSlukem ber_len_t s, d;
23622de962bdSlukem
23632de962bdSlukem assert( val != NULL );
23642de962bdSlukem assert( str != NULL );
23652de962bdSlukem assert( len != NULL );
23662de962bdSlukem
23672de962bdSlukem if ( val->bv_len == 0 ) {
23682de962bdSlukem *len = 0;
23692de962bdSlukem return( 0 );
23702de962bdSlukem }
23712de962bdSlukem
23722de962bdSlukem if ( flags & LDAP_AVA_NONPRINTABLE ) {
23732de962bdSlukem /*
23742de962bdSlukem * FIXME: Turn the value into a binary encoded BER?
23752de962bdSlukem */
23762de962bdSlukem *len = 0;
23772de962bdSlukem return( -1 );
23782de962bdSlukem
23792de962bdSlukem } else {
23802de962bdSlukem
23812de962bdSlukem /*
23822de962bdSlukem * we assume the string has enough room for the hex encoding
23832de962bdSlukem * of the value
23842de962bdSlukem */
23852de962bdSlukem
23862de962bdSlukem for ( s = 0, d = 0; s < val->bv_len; ) {
23872de962bdSlukem if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
23882de962bdSlukem str[ d++ ] = '\\';
23892de962bdSlukem }
23902de962bdSlukem str[ d++ ] = val->bv_val[ s++ ];
23912de962bdSlukem }
23922de962bdSlukem }
23932de962bdSlukem
23942de962bdSlukem *len = d;
23952de962bdSlukem
23962de962bdSlukem return( 0 );
23972de962bdSlukem }
23982de962bdSlukem
23992de962bdSlukem /*
24002de962bdSlukem * Length of the (supposedly) AD canonical string representation,
24012de962bdSlukem * accounting for chars that need to be escaped
24022de962bdSlukem */
24032de962bdSlukem static int
24042de962bdSlukem strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
24052de962bdSlukem {
24062de962bdSlukem ber_len_t l, cl;
24072de962bdSlukem char *p;
24082de962bdSlukem
24092de962bdSlukem assert( val != NULL );
24102de962bdSlukem assert( len != NULL );
24112de962bdSlukem
24122de962bdSlukem *len = 0;
24132de962bdSlukem if ( val->bv_len == 0 ) {
24142de962bdSlukem return( 0 );
24152de962bdSlukem }
24162de962bdSlukem
24172de962bdSlukem for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
24182de962bdSlukem cl = LDAP_UTF8_CHARLEN2( p, cl );
24192de962bdSlukem if ( cl == 0 ) {
24202de962bdSlukem /* illegal utf-8 char */
24212de962bdSlukem return -1;
24222de962bdSlukem } else if ( (cl == 1) && LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
24232de962bdSlukem l += 2;
24242de962bdSlukem } else {
24252de962bdSlukem l += cl;
24262de962bdSlukem }
24272de962bdSlukem }
24282de962bdSlukem
24292de962bdSlukem *len = l;
24302de962bdSlukem
24312de962bdSlukem return( 0 );
24322de962bdSlukem }
24332de962bdSlukem
24342de962bdSlukem /*
24352de962bdSlukem * convert to (supposedly) AD string representation,
24362de962bdSlukem * assume the destination has enough room for escaping
24372de962bdSlukem */
24382de962bdSlukem static int
24392de962bdSlukem strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
24402de962bdSlukem {
24412de962bdSlukem ber_len_t s, d, cl;
24422de962bdSlukem
24432de962bdSlukem assert( val != NULL );
24442de962bdSlukem assert( str != NULL );
24452de962bdSlukem assert( len != NULL );
24462de962bdSlukem
24472de962bdSlukem if ( val->bv_len == 0 ) {
24482de962bdSlukem *len = 0;
24492de962bdSlukem return( 0 );
24502de962bdSlukem }
24512de962bdSlukem
24522de962bdSlukem /*
24532de962bdSlukem * we assume the string has enough room for the escaping
24542de962bdSlukem * of the value
24552de962bdSlukem */
24562de962bdSlukem
24572de962bdSlukem for ( s = 0, d = 0; s < val->bv_len; ) {
24582de962bdSlukem cl = LDAP_UTF8_CHARLEN2( val->bv_val+s, cl );
24592de962bdSlukem if ( cl == 0 ) {
24602de962bdSlukem /* illegal utf-8 char */
24612de962bdSlukem return -1;
24622de962bdSlukem } else if ( (cl == 1) && LDAP_DN_NEEDESCAPE_AD(val->bv_val[ s ]) ) {
24632de962bdSlukem str[ d++ ] = '\\';
24642de962bdSlukem }
24652de962bdSlukem for (; cl--;) {
24662de962bdSlukem str[ d++ ] = val->bv_val[ s++ ];
24672de962bdSlukem }
24682de962bdSlukem }
24692de962bdSlukem
24702de962bdSlukem *len = d;
24712de962bdSlukem
24722de962bdSlukem return( 0 );
24732de962bdSlukem }
24742de962bdSlukem
24752de962bdSlukem /*
24762de962bdSlukem * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
24772de962bdSlukem * the first part of the AD representation of the DN is written in DNS
24782de962bdSlukem * form, i.e. dot separated domain name components (as suggested
24792de962bdSlukem * by Luke Howard, http://www.padl.com/~lukeh)
24802de962bdSlukem */
24812de962bdSlukem static int
24822de962bdSlukem dn2domain( LDAPDN dn, struct berval *bv, int pos, int *iRDN )
24832de962bdSlukem {
24842de962bdSlukem int i;
24852de962bdSlukem int domain = 0, first = 1;
24862de962bdSlukem ber_len_t l = 1; /* we move the null also */
24872de962bdSlukem char *str;
24882de962bdSlukem
24892de962bdSlukem /* we are guaranteed there's enough memory in str */
24902de962bdSlukem
24912de962bdSlukem /* sanity */
24922de962bdSlukem assert( dn != NULL );
24932de962bdSlukem assert( bv != NULL );
24942de962bdSlukem assert( iRDN != NULL );
24952de962bdSlukem assert( *iRDN >= 0 );
24962de962bdSlukem
24972de962bdSlukem str = bv->bv_val + pos;
24982de962bdSlukem
24992de962bdSlukem for ( i = *iRDN; i >= 0; i-- ) {
25002de962bdSlukem LDAPRDN rdn;
25012de962bdSlukem LDAPAVA *ava;
25022de962bdSlukem
25032de962bdSlukem assert( dn[ i ] != NULL );
25042de962bdSlukem rdn = dn[ i ];
25052de962bdSlukem
25062de962bdSlukem assert( rdn[ 0 ] != NULL );
25072de962bdSlukem ava = rdn[ 0 ];
25082de962bdSlukem
25092de962bdSlukem if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
25102de962bdSlukem break;
25112de962bdSlukem }
25122de962bdSlukem
25134e27b3e8Schristos if ( ldif_is_not_printable( ava->la_value.bv_val, ava->la_value.bv_len ) ) {
25144e27b3e8Schristos domain = 0;
25154e27b3e8Schristos break;
25164e27b3e8Schristos }
25174e27b3e8Schristos
25182de962bdSlukem domain = 1;
25192de962bdSlukem
25202de962bdSlukem if ( first ) {
25212de962bdSlukem first = 0;
25222de962bdSlukem AC_MEMCPY( str, ava->la_value.bv_val,
25232de962bdSlukem ava->la_value.bv_len + 1);
25242de962bdSlukem l += ava->la_value.bv_len;
25252de962bdSlukem
25262de962bdSlukem } else {
25272de962bdSlukem AC_MEMCPY( str + ava->la_value.bv_len + 1, bv->bv_val + pos, l);
25282de962bdSlukem AC_MEMCPY( str, ava->la_value.bv_val,
25292de962bdSlukem ava->la_value.bv_len );
25302de962bdSlukem str[ ava->la_value.bv_len ] = '.';
25312de962bdSlukem l += ava->la_value.bv_len + 1;
25322de962bdSlukem }
25332de962bdSlukem }
25342de962bdSlukem
25352de962bdSlukem *iRDN = i;
25362de962bdSlukem bv->bv_len = pos + l - 1;
25372de962bdSlukem
25382de962bdSlukem return( domain );
25392de962bdSlukem }
25402de962bdSlukem
25412de962bdSlukem static int
25422de962bdSlukem rdn2strlen( LDAPRDN rdn, unsigned flags, ber_len_t *len,
25432de962bdSlukem int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
25442de962bdSlukem {
25452de962bdSlukem int iAVA;
25462de962bdSlukem ber_len_t l = 0;
25472de962bdSlukem
25482de962bdSlukem *len = 0;
25492de962bdSlukem
25502de962bdSlukem for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
25512de962bdSlukem LDAPAVA *ava = rdn[ iAVA ];
25522de962bdSlukem
25532de962bdSlukem /* len(type) + '=' + '+' | ',' */
25542de962bdSlukem l += ava->la_attr.bv_len + 2;
25552de962bdSlukem
25562de962bdSlukem if ( ava->la_flags & LDAP_AVA_BINARY ) {
25572de962bdSlukem /* octothorpe + twice the length */
25582de962bdSlukem l += 1 + 2 * ava->la_value.bv_len;
25592de962bdSlukem
25602de962bdSlukem } else {
25612de962bdSlukem ber_len_t vl;
25622de962bdSlukem unsigned f = flags | ava->la_flags;
25632de962bdSlukem
25642de962bdSlukem if ( ( *s2l )( &ava->la_value, f, &vl ) ) {
25652de962bdSlukem return( -1 );
25662de962bdSlukem }
25672de962bdSlukem l += vl;
25682de962bdSlukem }
25692de962bdSlukem }
25702de962bdSlukem
25712de962bdSlukem *len = l;
25722de962bdSlukem
25732de962bdSlukem return( 0 );
25742de962bdSlukem }
25752de962bdSlukem
25762de962bdSlukem static int
25772de962bdSlukem rdn2str( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len,
25782de962bdSlukem int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
25792de962bdSlukem {
25802de962bdSlukem int iAVA;
25812de962bdSlukem ber_len_t l = 0;
25822de962bdSlukem
25832de962bdSlukem for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
25842de962bdSlukem LDAPAVA *ava = rdn[ iAVA ];
25852de962bdSlukem
25862de962bdSlukem AC_MEMCPY( &str[ l ], ava->la_attr.bv_val,
25872de962bdSlukem ava->la_attr.bv_len );
25882de962bdSlukem l += ava->la_attr.bv_len;
25892de962bdSlukem
25902de962bdSlukem str[ l++ ] = '=';
25912de962bdSlukem
25922de962bdSlukem if ( ava->la_flags & LDAP_AVA_BINARY ) {
25932de962bdSlukem str[ l++ ] = '#';
25942de962bdSlukem if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
25952de962bdSlukem return( -1 );
25962de962bdSlukem }
25972de962bdSlukem l += 2 * ava->la_value.bv_len;
25982de962bdSlukem
25992de962bdSlukem } else {
26002de962bdSlukem ber_len_t vl;
26012de962bdSlukem unsigned f = flags | ava->la_flags;
26022de962bdSlukem
26032de962bdSlukem if ( ( *s2s )( &ava->la_value, &str[ l ], f, &vl ) ) {
26042de962bdSlukem return( -1 );
26052de962bdSlukem }
26062de962bdSlukem l += vl;
26072de962bdSlukem }
26082de962bdSlukem str[ l++ ] = ( rdn[ iAVA + 1] ? '+' : ',' );
26092de962bdSlukem }
26102de962bdSlukem
26112de962bdSlukem *len = l;
26122de962bdSlukem
26132de962bdSlukem return( 0 );
26142de962bdSlukem }
26152de962bdSlukem
26162de962bdSlukem static int
26172de962bdSlukem rdn2DCEstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len )
26182de962bdSlukem {
26192de962bdSlukem int iAVA;
26202de962bdSlukem ber_len_t l = 0;
26212de962bdSlukem
26222de962bdSlukem *len = 0;
26232de962bdSlukem
26242de962bdSlukem for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
26252de962bdSlukem LDAPAVA *ava = rdn[ iAVA ];
26262de962bdSlukem
26272de962bdSlukem /* len(type) + '=' + ',' | '/' */
26282de962bdSlukem l += ava->la_attr.bv_len + 2;
26292de962bdSlukem
26302de962bdSlukem if ( ava->la_flags & LDAP_AVA_BINARY ) {
26312de962bdSlukem /* octothorpe + twice the length */
26322de962bdSlukem l += 1 + 2 * ava->la_value.bv_len;
26332de962bdSlukem } else {
26342de962bdSlukem ber_len_t vl;
26352de962bdSlukem unsigned f = flags | ava->la_flags;
26362de962bdSlukem
26372de962bdSlukem if ( strval2DCEstrlen( &ava->la_value, f, &vl ) ) {
26382de962bdSlukem return( -1 );
26392de962bdSlukem }
26402de962bdSlukem l += vl;
26412de962bdSlukem }
26422de962bdSlukem }
26432de962bdSlukem
26442de962bdSlukem *len = l;
26452de962bdSlukem
26462de962bdSlukem return( 0 );
26472de962bdSlukem }
26482de962bdSlukem
26492de962bdSlukem static int
26502de962bdSlukem rdn2DCEstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first )
26512de962bdSlukem {
26522de962bdSlukem int iAVA;
26532de962bdSlukem ber_len_t l = 0;
26542de962bdSlukem
26552de962bdSlukem for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
26562de962bdSlukem LDAPAVA *ava = rdn[ iAVA ];
26572de962bdSlukem
26582de962bdSlukem if ( first ) {
26592de962bdSlukem first = 0;
26602de962bdSlukem } else {
26612de962bdSlukem str[ l++ ] = ( iAVA ? ',' : '/' );
26622de962bdSlukem }
26632de962bdSlukem
26642de962bdSlukem AC_MEMCPY( &str[ l ], ava->la_attr.bv_val,
26652de962bdSlukem ava->la_attr.bv_len );
26662de962bdSlukem l += ava->la_attr.bv_len;
26672de962bdSlukem
26682de962bdSlukem str[ l++ ] = '=';
26692de962bdSlukem
26702de962bdSlukem if ( ava->la_flags & LDAP_AVA_BINARY ) {
26712de962bdSlukem str[ l++ ] = '#';
26722de962bdSlukem if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
26732de962bdSlukem return( -1 );
26742de962bdSlukem }
26752de962bdSlukem l += 2 * ava->la_value.bv_len;
26762de962bdSlukem } else {
26772de962bdSlukem ber_len_t vl;
26782de962bdSlukem unsigned f = flags | ava->la_flags;
26792de962bdSlukem
26802de962bdSlukem if ( strval2DCEstr( &ava->la_value, &str[ l ], f, &vl ) ) {
26812de962bdSlukem return( -1 );
26822de962bdSlukem }
26832de962bdSlukem l += vl;
26842de962bdSlukem }
26852de962bdSlukem }
26862de962bdSlukem
26872de962bdSlukem *len = l;
26882de962bdSlukem
26892de962bdSlukem return( 0 );
26902de962bdSlukem }
26912de962bdSlukem
26922de962bdSlukem static int
26932de962bdSlukem rdn2UFNstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len )
26942de962bdSlukem {
26952de962bdSlukem int iAVA;
26962de962bdSlukem ber_len_t l = 0;
26972de962bdSlukem
26982de962bdSlukem assert( rdn != NULL );
26992de962bdSlukem assert( len != NULL );
27002de962bdSlukem
27012de962bdSlukem *len = 0;
27022de962bdSlukem
27032de962bdSlukem for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
27042de962bdSlukem LDAPAVA *ava = rdn[ iAVA ];
27052de962bdSlukem
27062de962bdSlukem /* ' + ' | ', ' */
27072de962bdSlukem l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
27082de962bdSlukem
27092de962bdSlukem /* FIXME: are binary values allowed in UFN? */
27102de962bdSlukem if ( ava->la_flags & LDAP_AVA_BINARY ) {
27112de962bdSlukem /* octothorpe + twice the value */
27122de962bdSlukem l += 1 + 2 * ava->la_value.bv_len;
27132de962bdSlukem
27142de962bdSlukem } else {
27152de962bdSlukem ber_len_t vl;
27162de962bdSlukem unsigned f = flags | ava->la_flags;
27172de962bdSlukem
27182de962bdSlukem if ( strval2strlen( &ava->la_value, f, &vl ) ) {
27192de962bdSlukem return( -1 );
27202de962bdSlukem }
27212de962bdSlukem l += vl;
27222de962bdSlukem }
27232de962bdSlukem }
27242de962bdSlukem
27252de962bdSlukem *len = l;
27262de962bdSlukem
27272de962bdSlukem return( 0 );
27282de962bdSlukem }
27292de962bdSlukem
27302de962bdSlukem static int
27312de962bdSlukem rdn2UFNstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len )
27322de962bdSlukem {
27332de962bdSlukem int iAVA;
27342de962bdSlukem ber_len_t l = 0;
27352de962bdSlukem
27362de962bdSlukem for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
27372de962bdSlukem LDAPAVA *ava = rdn[ iAVA ];
27382de962bdSlukem
27392de962bdSlukem if ( ava->la_flags & LDAP_AVA_BINARY ) {
27402de962bdSlukem str[ l++ ] = '#';
27412de962bdSlukem if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
27422de962bdSlukem return( -1 );
27432de962bdSlukem }
27442de962bdSlukem l += 2 * ava->la_value.bv_len;
27452de962bdSlukem
27462de962bdSlukem } else {
27472de962bdSlukem ber_len_t vl;
27482de962bdSlukem unsigned f = flags | ava->la_flags;
27492de962bdSlukem
27502de962bdSlukem if ( strval2str( &ava->la_value, &str[ l ], f, &vl ) ) {
27512de962bdSlukem return( -1 );
27522de962bdSlukem }
27532de962bdSlukem l += vl;
27542de962bdSlukem }
27552de962bdSlukem
27562de962bdSlukem if ( rdn[ iAVA + 1 ] ) {
27572de962bdSlukem AC_MEMCPY( &str[ l ], " + ", 3 );
27582de962bdSlukem l += 3;
27592de962bdSlukem
27602de962bdSlukem } else {
27612de962bdSlukem AC_MEMCPY( &str[ l ], ", ", 2 );
27622de962bdSlukem l += 2;
27632de962bdSlukem }
27642de962bdSlukem }
27652de962bdSlukem
27662de962bdSlukem *len = l;
27672de962bdSlukem
27682de962bdSlukem return( 0 );
27692de962bdSlukem }
27702de962bdSlukem
27712de962bdSlukem static int
27722de962bdSlukem rdn2ADstrlen( LDAPRDN rdn, unsigned flags, ber_len_t *len )
27732de962bdSlukem {
27742de962bdSlukem int iAVA;
27752de962bdSlukem ber_len_t l = 0;
27762de962bdSlukem
27772de962bdSlukem assert( rdn != NULL );
27782de962bdSlukem assert( len != NULL );
27792de962bdSlukem
27802de962bdSlukem *len = 0;
27812de962bdSlukem
27822de962bdSlukem for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
27832de962bdSlukem LDAPAVA *ava = rdn[ iAVA ];
27842de962bdSlukem
27852de962bdSlukem /* ',' | '/' */
27862de962bdSlukem l++;
27872de962bdSlukem
27882de962bdSlukem /* FIXME: are binary values allowed in UFN? */
27892de962bdSlukem if ( ava->la_flags & LDAP_AVA_BINARY ) {
27902de962bdSlukem /* octothorpe + twice the value */
27912de962bdSlukem l += 1 + 2 * ava->la_value.bv_len;
27922de962bdSlukem } else {
27932de962bdSlukem ber_len_t vl;
27942de962bdSlukem unsigned f = flags | ava->la_flags;
27952de962bdSlukem
27962de962bdSlukem if ( strval2ADstrlen( &ava->la_value, f, &vl ) ) {
27972de962bdSlukem return( -1 );
27982de962bdSlukem }
27992de962bdSlukem l += vl;
28002de962bdSlukem }
28012de962bdSlukem }
28022de962bdSlukem
28032de962bdSlukem *len = l;
28042de962bdSlukem
28052de962bdSlukem return( 0 );
28062de962bdSlukem }
28072de962bdSlukem
28082de962bdSlukem static int
28092de962bdSlukem rdn2ADstr( LDAPRDN rdn, char *str, unsigned flags, ber_len_t *len, int first )
28102de962bdSlukem {
28112de962bdSlukem int iAVA;
28122de962bdSlukem ber_len_t l = 0;
28132de962bdSlukem
28142de962bdSlukem for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
28152de962bdSlukem LDAPAVA *ava = rdn[ iAVA ];
28162de962bdSlukem
28172de962bdSlukem if ( first ) {
28182de962bdSlukem first = 0;
28192de962bdSlukem } else {
28202de962bdSlukem str[ l++ ] = ( iAVA ? ',' : '/' );
28212de962bdSlukem }
28222de962bdSlukem
28232de962bdSlukem if ( ava->la_flags & LDAP_AVA_BINARY ) {
28242de962bdSlukem str[ l++ ] = '#';
28252de962bdSlukem if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
28262de962bdSlukem return( -1 );
28272de962bdSlukem }
28282de962bdSlukem l += 2 * ava->la_value.bv_len;
28292de962bdSlukem } else {
28302de962bdSlukem ber_len_t vl;
28312de962bdSlukem unsigned f = flags | ava->la_flags;
28322de962bdSlukem
28332de962bdSlukem if ( strval2ADstr( &ava->la_value, &str[ l ], f, &vl ) ) {
28342de962bdSlukem return( -1 );
28352de962bdSlukem }
28362de962bdSlukem l += vl;
28372de962bdSlukem }
28382de962bdSlukem }
28392de962bdSlukem
28402de962bdSlukem *len = l;
28412de962bdSlukem
28422de962bdSlukem return( 0 );
28432de962bdSlukem }
28442de962bdSlukem
28452de962bdSlukem /*
28462de962bdSlukem * ldap_rdn2str
28472de962bdSlukem *
28482de962bdSlukem * Returns in str a string representation of rdn based on flags.
28492de962bdSlukem * There is some duplication of code between this and ldap_dn2str;
28502de962bdSlukem * this is wanted to reduce the allocation of temporary buffers.
28512de962bdSlukem */
28522de962bdSlukem int
28532de962bdSlukem ldap_rdn2str( LDAPRDN rdn, char **str, unsigned flags )
28542de962bdSlukem {
28552de962bdSlukem struct berval bv;
28562de962bdSlukem int rc;
28572de962bdSlukem
28582de962bdSlukem assert( str != NULL );
28592de962bdSlukem
28602de962bdSlukem if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
28612de962bdSlukem return LDAP_PARAM_ERROR;
28622de962bdSlukem }
28632de962bdSlukem
28642de962bdSlukem rc = ldap_rdn2bv_x( rdn, &bv, flags, NULL );
28652de962bdSlukem *str = bv.bv_val;
28662de962bdSlukem return rc;
28672de962bdSlukem }
28682de962bdSlukem
28692de962bdSlukem int
28702de962bdSlukem ldap_rdn2bv( LDAPRDN rdn, struct berval *bv, unsigned flags )
28712de962bdSlukem {
28722de962bdSlukem return ldap_rdn2bv_x( rdn, bv, flags, NULL );
28732de962bdSlukem }
28742de962bdSlukem
28752de962bdSlukem int
28762de962bdSlukem ldap_rdn2bv_x( LDAPRDN rdn, struct berval *bv, unsigned flags, void *ctx )
28772de962bdSlukem {
28782de962bdSlukem int rc, back;
28792de962bdSlukem ber_len_t l;
28802de962bdSlukem
28812de962bdSlukem assert( bv != NULL );
28822de962bdSlukem
28832de962bdSlukem bv->bv_len = 0;
28842de962bdSlukem bv->bv_val = NULL;
28852de962bdSlukem
28862de962bdSlukem if ( rdn == NULL ) {
28872de962bdSlukem bv->bv_val = LDAP_STRDUPX( "", ctx );
28882de962bdSlukem return( LDAP_SUCCESS );
28892de962bdSlukem }
28902de962bdSlukem
28912de962bdSlukem /*
28922de962bdSlukem * This routine wastes "back" bytes at the end of the string
28932de962bdSlukem */
28942de962bdSlukem
28952de962bdSlukem switch ( LDAP_DN_FORMAT( flags ) ) {
28962de962bdSlukem case LDAP_DN_FORMAT_LDAPV3:
28972de962bdSlukem if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
28982de962bdSlukem return LDAP_DECODING_ERROR;
28992de962bdSlukem }
29002de962bdSlukem break;
29012de962bdSlukem
29022de962bdSlukem case LDAP_DN_FORMAT_LDAPV2:
29032de962bdSlukem if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
29042de962bdSlukem return LDAP_DECODING_ERROR;
29052de962bdSlukem }
29062de962bdSlukem break;
29072de962bdSlukem
29082de962bdSlukem case LDAP_DN_FORMAT_UFN:
29092de962bdSlukem if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
29102de962bdSlukem return LDAP_DECODING_ERROR;
29112de962bdSlukem }
29122de962bdSlukem break;
29132de962bdSlukem
29142de962bdSlukem case LDAP_DN_FORMAT_DCE:
29152de962bdSlukem if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
29162de962bdSlukem return LDAP_DECODING_ERROR;
29172de962bdSlukem }
29182de962bdSlukem break;
29192de962bdSlukem
29202de962bdSlukem case LDAP_DN_FORMAT_AD_CANONICAL:
29212de962bdSlukem if ( rdn2ADstrlen( rdn, flags, &l ) ) {
29222de962bdSlukem return LDAP_DECODING_ERROR;
29232de962bdSlukem }
29242de962bdSlukem break;
29252de962bdSlukem
29262de962bdSlukem default:
29272de962bdSlukem return LDAP_PARAM_ERROR;
29282de962bdSlukem }
29292de962bdSlukem
29302de962bdSlukem bv->bv_val = LDAP_MALLOCX( l + 1, ctx );
2931*549b59edSchristos if ( bv->bv_val == NULL ) {
2932*549b59edSchristos return LDAP_NO_MEMORY;
2933*549b59edSchristos }
29342de962bdSlukem
29352de962bdSlukem switch ( LDAP_DN_FORMAT( flags ) ) {
29362de962bdSlukem case LDAP_DN_FORMAT_LDAPV3:
29372de962bdSlukem rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2str );
29382de962bdSlukem back = 1;
29392de962bdSlukem break;
29402de962bdSlukem
29412de962bdSlukem case LDAP_DN_FORMAT_LDAPV2:
29422de962bdSlukem rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2IA5str );
29432de962bdSlukem back = 1;
29442de962bdSlukem break;
29452de962bdSlukem
29462de962bdSlukem case LDAP_DN_FORMAT_UFN:
29472de962bdSlukem rc = rdn2UFNstr( rdn, bv->bv_val, flags, &l );
29482de962bdSlukem back = 2;
29492de962bdSlukem break;
29502de962bdSlukem
29512de962bdSlukem case LDAP_DN_FORMAT_DCE:
29522de962bdSlukem rc = rdn2DCEstr( rdn, bv->bv_val, flags, &l, 1 );
29532de962bdSlukem back = 0;
29542de962bdSlukem break;
29552de962bdSlukem
29562de962bdSlukem case LDAP_DN_FORMAT_AD_CANONICAL:
29572de962bdSlukem rc = rdn2ADstr( rdn, bv->bv_val, flags, &l, 1 );
29582de962bdSlukem back = 0;
29592de962bdSlukem break;
29602de962bdSlukem
29612de962bdSlukem default:
29622de962bdSlukem /* need at least one of the previous */
29632de962bdSlukem return LDAP_PARAM_ERROR;
29642de962bdSlukem }
29652de962bdSlukem
29662de962bdSlukem if ( rc ) {
29672de962bdSlukem LDAP_FREEX( bv->bv_val, ctx );
29682de962bdSlukem return rc;
29692de962bdSlukem }
29702de962bdSlukem
29712de962bdSlukem bv->bv_len = l - back;
29722de962bdSlukem bv->bv_val[ bv->bv_len ] = '\0';
29732de962bdSlukem
29742de962bdSlukem return LDAP_SUCCESS;
29752de962bdSlukem }
29762de962bdSlukem
29772de962bdSlukem /*
29782de962bdSlukem * Very bulk implementation; many optimizations can be performed
29792de962bdSlukem * - a NULL dn results in an empty string ""
29802de962bdSlukem *
29812de962bdSlukem * FIXME: doubts
29822de962bdSlukem * a) what do we do if a UTF-8 string must be converted in LDAPv2?
29832de962bdSlukem * we must encode it in binary form ('#' + HEXPAIRs)
29842de962bdSlukem * b) does DCE/AD support UTF-8?
29852de962bdSlukem * no clue; don't think so.
29862de962bdSlukem * c) what do we do when binary values must be converted in UTF/DCE/AD?
29872de962bdSlukem * use binary encoded BER
29882de962bdSlukem */
29892de962bdSlukem int ldap_dn2str( LDAPDN dn, char **str, unsigned flags )
29902de962bdSlukem {
29912de962bdSlukem struct berval bv;
29922de962bdSlukem int rc;
29932de962bdSlukem
29942de962bdSlukem assert( str != NULL );
29952de962bdSlukem
29962de962bdSlukem if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
29972de962bdSlukem return LDAP_PARAM_ERROR;
29982de962bdSlukem }
29992de962bdSlukem
30002de962bdSlukem rc = ldap_dn2bv_x( dn, &bv, flags, NULL );
30012de962bdSlukem *str = bv.bv_val;
30022de962bdSlukem return rc;
30032de962bdSlukem }
30042de962bdSlukem
30052de962bdSlukem int ldap_dn2bv( LDAPDN dn, struct berval *bv, unsigned flags )
30062de962bdSlukem {
30072de962bdSlukem return ldap_dn2bv_x( dn, bv, flags, NULL );
30082de962bdSlukem }
30092de962bdSlukem
30102de962bdSlukem int ldap_dn2bv_x( LDAPDN dn, struct berval *bv, unsigned flags, void *ctx )
30112de962bdSlukem {
30122de962bdSlukem int iRDN;
30132de962bdSlukem int rc = LDAP_ENCODING_ERROR;
30142de962bdSlukem ber_len_t len, l;
30152de962bdSlukem
30162de962bdSlukem /* stringifying helpers for LDAPv3/LDAPv2 */
30172de962bdSlukem int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
30182de962bdSlukem int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
30192de962bdSlukem
30202de962bdSlukem assert( bv != NULL );
30212de962bdSlukem bv->bv_len = 0;
30222de962bdSlukem bv->bv_val = NULL;
30232de962bdSlukem
3024*549b59edSchristos Debug1( LDAP_DEBUG_ARGS, "=> ldap_dn2bv(%u)\n", flags );
30252de962bdSlukem
30262de962bdSlukem /*
30272de962bdSlukem * a null dn means an empty dn string
30282de962bdSlukem * FIXME: better raise an error?
30292de962bdSlukem */
3030d11b170bStron if ( dn == NULL || dn[0] == NULL ) {
30312de962bdSlukem bv->bv_val = LDAP_STRDUPX( "", ctx );
30322de962bdSlukem return( LDAP_SUCCESS );
30332de962bdSlukem }
30342de962bdSlukem
30352de962bdSlukem switch ( LDAP_DN_FORMAT( flags ) ) {
30362de962bdSlukem case LDAP_DN_FORMAT_LDAPV3:
30372de962bdSlukem sv2l = strval2strlen;
30382de962bdSlukem sv2s = strval2str;
30392de962bdSlukem
30402de962bdSlukem if( 0 ) {
30412de962bdSlukem case LDAP_DN_FORMAT_LDAPV2:
30422de962bdSlukem sv2l = strval2IA5strlen;
30432de962bdSlukem sv2s = strval2IA5str;
30442de962bdSlukem }
30452de962bdSlukem
30462de962bdSlukem for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
30472de962bdSlukem ber_len_t rdnl;
30482de962bdSlukem if ( rdn2strlen( dn[ iRDN ], flags, &rdnl, sv2l ) ) {
30492de962bdSlukem goto return_results;
30502de962bdSlukem }
30512de962bdSlukem
30522de962bdSlukem len += rdnl;
30532de962bdSlukem }
30542de962bdSlukem
30552de962bdSlukem if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) {
30562de962bdSlukem rc = LDAP_NO_MEMORY;
30572de962bdSlukem break;
30582de962bdSlukem }
30592de962bdSlukem
30602de962bdSlukem for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
30612de962bdSlukem ber_len_t rdnl;
30622de962bdSlukem
30632de962bdSlukem if ( rdn2str( dn[ iRDN ], &bv->bv_val[ l ], flags,
30642de962bdSlukem &rdnl, sv2s ) ) {
30652de962bdSlukem LDAP_FREEX( bv->bv_val, ctx );
30662de962bdSlukem bv->bv_val = NULL;
30672de962bdSlukem goto return_results;
30682de962bdSlukem }
30692de962bdSlukem l += rdnl;
30702de962bdSlukem }
30712de962bdSlukem
30722de962bdSlukem assert( l == len );
30732de962bdSlukem
30742de962bdSlukem /*
30752de962bdSlukem * trim the last ',' (the allocated memory
30762de962bdSlukem * is one byte longer than required)
30772de962bdSlukem */
30782de962bdSlukem bv->bv_len = len - 1;
30792de962bdSlukem bv->bv_val[ bv->bv_len ] = '\0';
30802de962bdSlukem
30812de962bdSlukem rc = LDAP_SUCCESS;
30822de962bdSlukem break;
30832de962bdSlukem
30842de962bdSlukem case LDAP_DN_FORMAT_UFN: {
30852de962bdSlukem /*
30862de962bdSlukem * FIXME: quoting from RFC 1781:
30872de962bdSlukem *
30882de962bdSlukem To take a distinguished name, and generate a name of this format with
30892de962bdSlukem attribute types omitted, the following steps are followed.
30902de962bdSlukem
30912de962bdSlukem 1. If the first attribute is of type CommonName, the type may be
30922de962bdSlukem omitted.
30932de962bdSlukem
30942de962bdSlukem 2. If the last attribute is of type Country, the type may be
30952de962bdSlukem omitted.
30962de962bdSlukem
30972de962bdSlukem 3. If the last attribute is of type Country, the last
30982de962bdSlukem Organisation attribute may have the type omitted.
30992de962bdSlukem
31002de962bdSlukem 4. All attributes of type OrganisationalUnit may have the type
31012de962bdSlukem omitted, unless they are after an Organisation attribute or
31022de962bdSlukem the first attribute is of type OrganisationalUnit.
31032de962bdSlukem
31042de962bdSlukem * this should be the pedantic implementation.
31052de962bdSlukem *
31062de962bdSlukem * Here the standard implementation reflects
31072de962bdSlukem * the one historically provided by OpenLDAP
31082de962bdSlukem * (and UMIch, I presume), with the variant
31092de962bdSlukem * of spaces and plusses (' + ') separating
31102de962bdSlukem * rdn components.
31112de962bdSlukem *
31122de962bdSlukem * A non-standard but nice implementation could
31132de962bdSlukem * be to turn the final "dc" attributes into a
31142de962bdSlukem * dot-separated domain.
31152de962bdSlukem *
31162de962bdSlukem * Other improvements could involve the use of
31172de962bdSlukem * friendly country names and so.
31182de962bdSlukem */
31192de962bdSlukem #ifdef DC_IN_UFN
31202de962bdSlukem int leftmost_dc = -1;
31212de962bdSlukem int last_iRDN = -1;
31222de962bdSlukem #endif /* DC_IN_UFN */
31232de962bdSlukem
31242de962bdSlukem for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
31252de962bdSlukem ber_len_t rdnl;
31262de962bdSlukem
31272de962bdSlukem if ( rdn2UFNstrlen( dn[ iRDN ], flags, &rdnl ) ) {
31282de962bdSlukem goto return_results;
31292de962bdSlukem }
31302de962bdSlukem len += rdnl;
31312de962bdSlukem
31322de962bdSlukem #ifdef DC_IN_UFN
31332de962bdSlukem if ( LDAP_DN_IS_RDN_DC( dn[ iRDN ] ) ) {
31342de962bdSlukem if ( leftmost_dc == -1 ) {
31352de962bdSlukem leftmost_dc = iRDN;
31362de962bdSlukem }
31372de962bdSlukem } else {
31382de962bdSlukem leftmost_dc = -1;
31392de962bdSlukem }
31402de962bdSlukem #endif /* DC_IN_UFN */
31412de962bdSlukem }
31422de962bdSlukem
31432de962bdSlukem if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) {
31442de962bdSlukem rc = LDAP_NO_MEMORY;
31452de962bdSlukem break;
31462de962bdSlukem }
31472de962bdSlukem
31482de962bdSlukem #ifdef DC_IN_UFN
31492de962bdSlukem if ( leftmost_dc == -1 ) {
31502de962bdSlukem #endif /* DC_IN_UFN */
31512de962bdSlukem for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
31522de962bdSlukem ber_len_t vl;
31532de962bdSlukem
31542de962bdSlukem if ( rdn2UFNstr( dn[ iRDN ], &bv->bv_val[ l ],
31552de962bdSlukem flags, &vl ) ) {
31562de962bdSlukem LDAP_FREEX( bv->bv_val, ctx );
31572de962bdSlukem bv->bv_val = NULL;
31582de962bdSlukem goto return_results;
31592de962bdSlukem }
31602de962bdSlukem l += vl;
31612de962bdSlukem }
31622de962bdSlukem
31632de962bdSlukem /*
31642de962bdSlukem * trim the last ', ' (the allocated memory
31652de962bdSlukem * is two bytes longer than required)
31662de962bdSlukem */
31672de962bdSlukem bv->bv_len = len - 2;
31682de962bdSlukem bv->bv_val[ bv->bv_len ] = '\0';
31692de962bdSlukem #ifdef DC_IN_UFN
31702de962bdSlukem } else {
31712de962bdSlukem last_iRDN = iRDN - 1;
31722de962bdSlukem
31732de962bdSlukem for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
31742de962bdSlukem ber_len_t vl;
31752de962bdSlukem
31762de962bdSlukem if ( rdn2UFNstr( dn[ iRDN ], &bv->bv_val[ l ],
31772de962bdSlukem flags, &vl ) ) {
31782de962bdSlukem LDAP_FREEX( bv->bv_val, ctx );
31792de962bdSlukem bv->bv_val = NULL;
31802de962bdSlukem goto return_results;
31812de962bdSlukem }
31822de962bdSlukem l += vl;
31832de962bdSlukem }
31842de962bdSlukem
31852de962bdSlukem if ( !dn2domain( dn, bv, l, &last_iRDN ) ) {
31862de962bdSlukem LDAP_FREEX( bv->bv_val, ctx );
31872de962bdSlukem bv->bv_val = NULL;
31882de962bdSlukem goto return_results;
31892de962bdSlukem }
31902de962bdSlukem
31912de962bdSlukem /* the string is correctly terminated by dn2domain */
31922de962bdSlukem }
31932de962bdSlukem #endif /* DC_IN_UFN */
31942de962bdSlukem
31952de962bdSlukem rc = LDAP_SUCCESS;
31962de962bdSlukem
31972de962bdSlukem } break;
31982de962bdSlukem
31992de962bdSlukem case LDAP_DN_FORMAT_DCE:
32002de962bdSlukem for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
32012de962bdSlukem ber_len_t rdnl;
32022de962bdSlukem if ( rdn2DCEstrlen( dn[ iRDN ], flags, &rdnl ) ) {
32032de962bdSlukem goto return_results;
32042de962bdSlukem }
32052de962bdSlukem
32062de962bdSlukem len += rdnl;
32072de962bdSlukem }
32082de962bdSlukem
32092de962bdSlukem if ( ( bv->bv_val = LDAP_MALLOCX( len + 1, ctx ) ) == NULL ) {
32102de962bdSlukem rc = LDAP_NO_MEMORY;
32112de962bdSlukem break;
32122de962bdSlukem }
32132de962bdSlukem
32142de962bdSlukem for ( l = 0; iRDN--; ) {
32152de962bdSlukem ber_len_t rdnl;
32162de962bdSlukem
32172de962bdSlukem if ( rdn2DCEstr( dn[ iRDN ], &bv->bv_val[ l ], flags,
32182de962bdSlukem &rdnl, 0 ) ) {
32192de962bdSlukem LDAP_FREEX( bv->bv_val, ctx );
32202de962bdSlukem bv->bv_val = NULL;
32212de962bdSlukem goto return_results;
32222de962bdSlukem }
32232de962bdSlukem l += rdnl;
32242de962bdSlukem }
32252de962bdSlukem
32262de962bdSlukem assert( l == len );
32272de962bdSlukem
32282de962bdSlukem bv->bv_len = len;
32292de962bdSlukem bv->bv_val[ bv->bv_len ] = '\0';
32302de962bdSlukem
32312de962bdSlukem rc = LDAP_SUCCESS;
32322de962bdSlukem break;
32332de962bdSlukem
32342de962bdSlukem case LDAP_DN_FORMAT_AD_CANONICAL: {
32352de962bdSlukem int trailing_slash = 1;
32362de962bdSlukem
32372de962bdSlukem /*
32382de962bdSlukem * Sort of UFN for DCE DNs: a slash ('/') separated
32392de962bdSlukem * global->local DN with no types; strictly speaking,
32402de962bdSlukem * the naming context should be a domain, which is
3241*549b59edSchristos * written in DNS-style, e.g. dot-separated.
32422de962bdSlukem *
32432de962bdSlukem * Example:
32442de962bdSlukem *
32452de962bdSlukem * "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
32462de962bdSlukem *
32472de962bdSlukem * will read
32482de962bdSlukem *
32492de962bdSlukem * "microsoft.com/People/Bill,Gates"
32502de962bdSlukem */
32512de962bdSlukem for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
32522de962bdSlukem ber_len_t rdnl;
32532de962bdSlukem
32542de962bdSlukem if ( rdn2ADstrlen( dn[ iRDN ], flags, &rdnl ) ) {
32552de962bdSlukem goto return_results;
32562de962bdSlukem }
32572de962bdSlukem
32582de962bdSlukem len += rdnl;
32592de962bdSlukem }
32602de962bdSlukem
32612de962bdSlukem /* reserve room for trailing '/' in case the DN
32622de962bdSlukem * is exactly a domain */
32632de962bdSlukem if ( ( bv->bv_val = LDAP_MALLOCX( len + 1 + 1, ctx ) ) == NULL )
32642de962bdSlukem {
32652de962bdSlukem rc = LDAP_NO_MEMORY;
32662de962bdSlukem break;
32672de962bdSlukem }
32682de962bdSlukem
32692de962bdSlukem iRDN--;
32702de962bdSlukem if ( iRDN && dn2domain( dn, bv, 0, &iRDN ) != 0 ) {
32712de962bdSlukem for ( l = bv->bv_len; iRDN >= 0 ; iRDN-- ) {
32722de962bdSlukem ber_len_t rdnl;
32732de962bdSlukem
32742de962bdSlukem trailing_slash = 0;
32752de962bdSlukem
32762de962bdSlukem if ( rdn2ADstr( dn[ iRDN ], &bv->bv_val[ l ],
32772de962bdSlukem flags, &rdnl, 0 ) ) {
32782de962bdSlukem LDAP_FREEX( bv->bv_val, ctx );
32792de962bdSlukem bv->bv_val = NULL;
32802de962bdSlukem goto return_results;
32812de962bdSlukem }
32822de962bdSlukem l += rdnl;
32832de962bdSlukem }
32842de962bdSlukem
32852de962bdSlukem } else {
32862de962bdSlukem int first = 1;
32872de962bdSlukem
32882de962bdSlukem /*
32892de962bdSlukem * Strictly speaking, AD canonical requires
32902de962bdSlukem * a DN to be in the form "..., dc=smtg",
32912de962bdSlukem * i.e. terminated by a domain component
32922de962bdSlukem */
32932de962bdSlukem if ( flags & LDAP_DN_PEDANTIC ) {
32942de962bdSlukem LDAP_FREEX( bv->bv_val, ctx );
32952de962bdSlukem bv->bv_val = NULL;
32962de962bdSlukem rc = LDAP_ENCODING_ERROR;
32972de962bdSlukem break;
32982de962bdSlukem }
32992de962bdSlukem
33002de962bdSlukem for ( l = 0; iRDN >= 0 ; iRDN-- ) {
33012de962bdSlukem ber_len_t rdnl;
33022de962bdSlukem
33032de962bdSlukem if ( rdn2ADstr( dn[ iRDN ], &bv->bv_val[ l ],
33042de962bdSlukem flags, &rdnl, first ) ) {
33052de962bdSlukem LDAP_FREEX( bv->bv_val, ctx );
33062de962bdSlukem bv->bv_val = NULL;
33072de962bdSlukem goto return_results;
33082de962bdSlukem }
33092de962bdSlukem if ( first ) {
33102de962bdSlukem first = 0;
33112de962bdSlukem }
33122de962bdSlukem l += rdnl;
33132de962bdSlukem }
33142de962bdSlukem }
33152de962bdSlukem
33162de962bdSlukem if ( trailing_slash ) {
33172de962bdSlukem /* the DN is exactly a domain -- need a trailing
33182de962bdSlukem * slash; room was reserved in advance */
33192de962bdSlukem bv->bv_val[ len ] = '/';
33202de962bdSlukem len++;
33212de962bdSlukem }
33222de962bdSlukem
33232de962bdSlukem bv->bv_len = len;
33242de962bdSlukem bv->bv_val[ bv->bv_len ] = '\0';
33252de962bdSlukem
33262de962bdSlukem rc = LDAP_SUCCESS;
33272de962bdSlukem } break;
33282de962bdSlukem
33292de962bdSlukem default:
33302de962bdSlukem return LDAP_PARAM_ERROR;
33312de962bdSlukem }
33322de962bdSlukem
3333*549b59edSchristos Debug3( LDAP_DEBUG_ARGS, "<= ldap_dn2bv(%s)=%d %s\n",
33342de962bdSlukem bv->bv_val, rc, rc ? ldap_err2string( rc ) : "" );
33352de962bdSlukem
33362de962bdSlukem return_results:;
33372de962bdSlukem return( rc );
33382de962bdSlukem }
33392de962bdSlukem
3340