3 * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * Copyright (c) 1994 Regents of the University of Michigan.
17 #include <ac/stdlib.h>
18 #include <ac/socket.h>
19 #include <ac/string.h>
23 #include "ldap_schema.h"
25 /* extension to UFN that turns trailing "dc=value" rdns in DNS style,
26 * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */
30 /* parsing/printing routines */
31 static int str2strval( const char *str, struct berval *val,
32 const char **next, unsigned flags, unsigned *retFlags );
33 static int DCE2strval( const char *str, struct berval *val,
34 const char **next, unsigned flags );
35 static int IA52strval( const char *str, struct berval *val,
36 const char **next, unsigned flags );
37 static int quotedIA52strval( const char *str, struct berval *val,
38 const char **next, unsigned flags );
39 static int hexstr2binval( const char *str, struct berval *val,
40 const char **next, unsigned flags );
41 static int hexstr2bin( const char *str, char *c );
42 static int byte2hexpair( const char *val, char *pair );
43 static int binval2hexstr( struct berval *val, char *str );
44 static int strval2strlen( struct berval *val, unsigned flags,
46 static int strval2str( struct berval *val, char *str, unsigned flags,
48 static int strval2IA5strlen( struct berval *val, unsigned flags,
50 static int strval2IA5str( struct berval *val, char *str, unsigned flags,
52 static int strval2DCEstrlen( struct berval *val, unsigned flags,
54 static int strval2DCEstr( struct berval *val, char *str, unsigned flags,
56 static int strval2ADstrlen( struct berval *val, unsigned flags,
58 static int strval2ADstr( struct berval *val, char *str, unsigned flags,
60 static int dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN );
63 static LDAPAVA * ldapava_new(
64 const struct berval *attr, const struct berval *val, unsigned flags );
66 /* Higher level helpers */
67 static int rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
68 int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
69 static int rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
70 int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
71 static int rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
72 static int rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len );
73 static int rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
74 static int rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flag, ber_len_t *len, int first );
75 static int rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
76 static int rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first );
79 * RFC 1823 ldap_get_dn
82 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
87 Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
89 if ( entry == NULL ) {
90 ld->ld_errno = LDAP_PARAM_ERROR;
94 tmp = *entry->lm_ber; /* struct copy */
95 if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
96 ld->ld_errno = LDAP_DECODING_ERROR;
104 * RFC 1823 ldap_dn2ufn
107 ldap_dn2ufn( LDAP_CONST char *dn )
111 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
113 ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP,
114 &out, LDAP_DN_FORMAT_UFN );
120 * RFC 1823 ldap_explode_dn
123 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
126 char **values = NULL;
128 unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
130 Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
132 if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP )
137 if( tmpDN == NULL ) {
138 values = LDAP_MALLOC( sizeof( char * ) );
139 if( values == NULL ) return NULL;
145 for ( iRDN = 0; tmpDN[ 0 ][ iRDN ]; iRDN++ );
147 values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iRDN ) );
148 if ( values == NULL ) {
149 ldap_dnfree( tmpDN );
153 for ( iRDN = 0; tmpDN[ 0 ][ iRDN ]; iRDN++ ) {
154 ldap_rdn2str( tmpDN[ 0 ][ iRDN ], &values[ iRDN ], flag );
156 ldap_dnfree( tmpDN );
157 values[ iRDN ] = NULL;
163 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
166 char **values = NULL;
170 Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
173 * we only parse the first rdn
174 * FIXME: we prefer efficiency over checking if the _ENTIRE_
177 if ( ldap_str2rdn( rdn, &tmpRDN, (char **) &p, LDAP_DN_FORMAT_LDAP )
182 for ( iAVA = 0; tmpRDN[ 0 ][ iAVA ]; iAVA++ ) ;
183 values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iAVA ) );
184 if ( values == NULL ) {
185 ldap_rdnfree( tmpRDN );
189 for ( iAVA = 0; tmpRDN[ 0 ][ iAVA ]; iAVA++ ) {
190 ber_len_t l = 0, vl, al = 0;
192 LDAPAVA *ava = tmpRDN[ 0 ][ iAVA ];
194 if ( ava->la_flags == LDAP_AVA_BINARY ) {
195 vl = 1 + 2 * ava->la_value.bv_len;
198 if ( strval2strlen( &ava->la_value,
199 ava->la_flags, &vl ) ) {
205 al = ava->la_attr.bv_len;
206 l = vl + ava->la_attr.bv_len + 1;
208 str = LDAP_MALLOC( l + 1 );
209 AC_MEMCPY( str, ava->la_attr.bv_val,
210 ava->la_attr.bv_len );
215 str = LDAP_MALLOC( l + 1 );
218 if ( ava->la_flags == LDAP_AVA_BINARY ) {
220 if ( binval2hexstr( &ava->la_value, &str[ al ] ) ) {
225 if ( strval2str( &ava->la_value, &str[ al ],
226 ava->la_flags, &vl ) ) {
232 values[ iAVA ] = str;
234 values[ iAVA ] = NULL;
236 ldap_rdnfree( tmpRDN );
241 LBER_VFREE( values );
242 ldap_rdnfree( tmpRDN );
247 ldap_dn2dcedn( LDAP_CONST char *dn )
251 Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
253 ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP,
254 &out, LDAP_DN_FORMAT_DCE );
260 ldap_dcedn2dn( LDAP_CONST char *dce )
264 Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
266 ( void )ldap_dn_normalize( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
272 ldap_dn2ad_canonical( LDAP_CONST char *dn )
276 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
278 ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP,
279 &out, LDAP_DN_FORMAT_AD_CANONICAL );
285 * function that changes the string representation of dnin
286 * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
289 * LDAP_DN_FORMAT_LDAP (rfc 2253 and ldapbis liberal,
290 * plus some rfc 1779)
291 * LDAP_DN_FORMAT_LDAPV3 (rfc 2253 and ldapbis)
292 * LDAP_DN_FORMAT_LDAPV2 (rfc 1779)
293 * LDAP_DN_FORMAT_DCE (?)
295 * fout can be any of the above except
296 * LDAP_DN_FORMAT_LDAP
298 * LDAP_DN_FORMAT_UFN (rfc 1781, partial and with extensions)
299 * LDAP_DN_FORMAT_AD_CANONICAL (?)
302 ldap_dn_normalize( LDAP_CONST char *dnin,
303 unsigned fin, char **dnout, unsigned fout )
306 LDAPDN *tmpDN = NULL;
308 Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );
314 if ( dnin == NULL ) {
315 return( LDAP_SUCCESS );
318 rc = ldap_str2dn( dnin , &tmpDN, fin );
319 if ( rc != LDAP_SUCCESS ) {
323 rc = ldap_dn2str( tmpDN, dnout, fout );
325 ldap_dnfree( tmpDN );
333 /* #define B4ATTRTYPE 0x0001 */
334 #define B4OIDATTRTYPE 0x0002
335 #define B4STRINGATTRTYPE 0x0003
337 #define B4AVAEQUALS 0x0100
338 #define B4AVASEP 0x0200
339 #define B4RDNSEP 0x0300
340 #define GOTAVA 0x0400
342 #define B4ATTRVALUE 0x0010
343 #define B4STRINGVALUE 0x0020
344 #define B4IA5VALUEQUOTED 0x0030
345 #define B4IA5VALUE 0x0040
346 #define B4BINARYVALUE 0x0050
349 * Helpers (mostly from slap.h)
350 * c is assumed to Unicode in an ASCII compatible format (UTF-8)
351 * Macros assume "C" Locale (ASCII)
353 #define LDAP_DN_ASCII_SPACE(c) \
354 ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
355 #define LDAP_DN_ASCII_LOWER(c) LDAP_LOWER(c)
356 #define LDAP_DN_ASCII_UPPER(c) LDAP_UPPER(c)
357 #define LDAP_DN_ASCII_ALPHA(c) LDAP_ALPHA(c)
359 #define LDAP_DN_ASCII_DIGIT(c) LDAP_DIGIT(c)
360 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) LDAP_HEXLOWER(c)
361 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) LDAP_HEXUPPER(c)
362 #define LDAP_DN_ASCII_HEXDIGIT(c) LDAP_HEX(c)
363 #define LDAP_DN_ASCII_ALNUM(c) LDAP_ALNUM(c)
364 #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' )
367 #define LDAP_DN_OID_LEADCHAR(c) LDAP_DIGIT(c)
368 #define LDAP_DN_DESC_LEADCHAR(c) LDAP_ALPHA(c)
369 #define LDAP_DN_DESC_CHAR(c) LDAP_LDH(c)
370 #define LDAP_DN_LANG_SEP(c) ( (c) == ';' )
371 #define LDAP_DN_ATTRDESC_CHAR(c) \
372 ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
374 /* special symbols */
375 #define LDAP_DN_AVA_EQUALS(c) ( (c) == '=' )
376 #define LDAP_DN_AVA_SEP(c) ( (c) == '+' )
377 #define LDAP_DN_RDN_SEP(c) ( (c) == ',' )
378 #define LDAP_DN_RDN_SEP_V2(c) ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
379 #define LDAP_DN_OCTOTHORPE(c) ( (c) == '#' )
380 #define LDAP_DN_QUOTES(c) ( (c) == '\"' )
381 #define LDAP_DN_ESCAPE(c) ( (c) == '\\' )
382 #define LDAP_DN_VALUE_END(c) \
383 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
384 #define LDAP_DN_NE(c) \
385 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
386 || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
387 #define LDAP_DN_MAYESCAPE(c) \
388 ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) \
389 || LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) )
390 #define LDAP_DN_NEEDESCAPE(c) \
391 ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
392 #define LDAP_DN_NEEDESCAPE_LEAD(c) LDAP_DN_MAYESCAPE(c)
393 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
394 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
395 #define LDAP_DN_WILLESCAPE_CHAR(c) \
396 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) || LDAP_DN_ESCAPE(c) )
397 #define LDAP_DN_IS_PRETTY(f) ( (f) & LDAP_DN_PRETTY )
398 #define LDAP_DN_WILLESCAPE_HEX(f, c) \
399 ( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
402 #define LDAP_DN_VALUE_END_V2(c) \
403 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
405 #define LDAP_DN_V2_SPECIAL(c) \
406 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
407 || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
408 || LDAP_DN_OCTOTHORPE(c) )
409 #define LDAP_DN_V2_PAIR(c) \
410 ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
413 * DCE (mostly from Luke Howard and IBM implementation for AIX)
415 * From: "Application Development Guide - Directory Services" (FIXME: add link?)
416 * Here escapes and valid chars for GDS are considered; as soon as more
417 * specific info is found, the macros will be updated.
419 * Chars: 'a'-'z', 'A'-'Z', '0'-'9',
420 * '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
422 * Metachars: '/', ',', '=', '\'.
424 * the '\' is used to escape other metachars.
430 * Attribute types must start with alphabetic chars and can contain
431 * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
433 #define LDAP_DN_RDN_SEP_DCE(c) ( (c) == '/' )
434 #define LDAP_DN_AVA_SEP_DCE(c) ( (c) == ',' )
435 #define LDAP_DN_ESCAPE_DCE(c) ( LDAP_DN_ESCAPE(c) )
436 #define LDAP_DN_VALUE_END_DCE(c) \
437 ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
438 #define LDAP_DN_NEEDESCAPE_DCE(c) \
439 ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
442 #define LDAP_DN_RDN_SEP_AD(c) ( (c) == '/' )
443 #define LDAP_DN_ESCAPE_AD(c) ( LDAP_DN_ESCAPE(c) )
444 #define LDAP_DN_AVA_SEP_AD(c) ( (c) == ',' ) /* assume same as DCE */
445 #define LDAP_DN_VALUE_END_AD(c) \
446 ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
447 #define LDAP_DN_NEEDESCAPE_AD(c) \
448 ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
451 #define LDAP_DN_HEXPAIR(s) \
452 ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
453 /* better look at the AttributeDescription? */
455 /* FIXME: no composite rdn or non-"dc" types, right?
456 * (what about "dc" in OID form?) */
457 /* FIXME: we do not allow binary values in domain, right? */
458 /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
459 /* NOTE: don't use strcasecmp() as it is locale specific! */
460 #define LDAP_DC_ATTR "dc"
461 #define LDAP_DC_ATTRU "DC"
462 #define LDAP_DN_IS_RDN_DC( r ) \
463 ( (r) && (r)[0][0] && !(r)[0][1] \
464 && ((r)[0][0]->la_flags == LDAP_AVA_STRING) \
465 && ((r)[0][0]->la_attr.bv_len == 2) \
466 && (((r)[0][0]->la_attr.bv_val[0] == LDAP_DC_ATTR[0]) \
467 || ((r)[0][0]->la_attr.bv_val[0] == LDAP_DC_ATTRU[0])) \
468 && (((r)[0][0]->la_attr.bv_val[1] == LDAP_DC_ATTR[1]) \
469 || ((r)[0][0]->la_attr.bv_val[1] == LDAP_DC_ATTRU[1])))
471 /* Composite rules */
472 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
473 ( LDAP_DN_LDAPV2(f) \
474 || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
475 #define LDAP_DN_ALLOW_SPACES(f) \
476 ( LDAP_DN_LDAPV2(f) \
477 || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
478 #define LDAP_DN_LDAP(f) \
479 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
480 #define LDAP_DN_LDAPV3(f) \
481 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
482 #define LDAP_DN_LDAPV2(f) \
483 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
484 #define LDAP_DN_DCE(f) \
485 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
486 #define LDAP_DN_UFN(f) \
487 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
488 #define LDAP_DN_ADC(f) \
489 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
490 #define LDAP_DN_FORMAT(f) ( (f) & LDAP_DN_FORMAT_MASK )
493 * LDAPAVA helpers (will become part of the API for operations
494 * on structural representations of DNs).
497 ldapava_new( const struct berval *attr, const struct berval *val,
505 ava = LDAP_MALLOC( sizeof( LDAPAVA ) + attr->bv_len + 1 );
507 /* should we test it? */
512 ava->la_attr.bv_len = attr->bv_len;
513 ava->la_attr.bv_val = (char *)(ava+1);
514 AC_MEMCPY( ava->la_attr.bv_val, attr->bv_val, attr->bv_len );
515 ava->la_attr.bv_val[attr->bv_len] = '\0';
517 ava->la_value = *val;
518 ava->la_flags = flags;
520 ava->la_private = NULL;
526 ldap_avafree( LDAPAVA *ava )
531 /* ava's private must be freed by caller
532 * (at present let's skip this check because la_private
533 * basically holds static data) */
534 assert( ava->la_private == NULL );
538 /* la_attr is now contiguous with ava, not freed separately */
539 LDAP_FREE( ava->la_attr.bv_val );
541 LDAP_FREE( ava->la_value.bv_val );
547 ldap_rdnfree( LDAPRDN *rdn )
555 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
556 ldap_avafree( rdn[ 0 ][ iAVA ] );
563 ldap_dnfree( LDAPDN *dn )
571 for ( iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
572 ldap_rdnfree( dn[ 0 ][ iRDN ] );
579 * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
580 * into a structural representation of the DN, by separating attribute
581 * types and values encoded in the more appropriate form, which is
582 * string or OID for attribute types and binary form of the BER encoded
583 * value or Unicode string. Formats different from LDAPv3 are parsed
584 * according to their own rules and turned into the more appropriate
585 * form according to LDAPv3.
587 * NOTE: I realize the code is getting spaghettish; it is rather
588 * experimental and will hopefully turn into something more simple
589 * and readable as soon as it works as expected.
593 * Default sizes of AVA and RDN static working arrays; if required
594 * the are dynamically resized. The values can be tuned in case
595 * of special requirements (e.g. very deep DN trees or high number
598 #define TMP_AVA_SLOTS 8
599 #define TMP_RDN_SLOTS 32
602 ldap_str2dn( LDAP_CONST char *str, LDAPDN **dn, unsigned flags )
605 int rc = LDAP_DECODING_ERROR;
608 LDAPDN *newDN = NULL;
609 LDAPRDN *newRDN = NULL, *tmpDN_[TMP_RDN_SLOTS], **tmpDN = tmpDN_;
610 int num_slots = TMP_RDN_SLOTS;
615 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );
619 switch ( LDAP_DN_FORMAT( flags ) ) {
620 case LDAP_DN_FORMAT_LDAP:
621 case LDAP_DN_FORMAT_LDAPV3:
622 case LDAP_DN_FORMAT_LDAPV2:
623 case LDAP_DN_FORMAT_DCE:
626 /* unsupported in str2dn */
627 case LDAP_DN_FORMAT_UFN:
628 case LDAP_DN_FORMAT_AD_CANONICAL:
629 return LDAP_PARAM_ERROR;
631 case LDAP_DN_FORMAT_LBER:
633 return LDAP_PARAM_ERROR;
636 if ( str[ 0 ] == '\0' ) {
641 if ( LDAP_DN_DCE( flags ) ) {
644 * (from Luke Howard: thnx) A RDN separator is required
645 * at the beginning of an (absolute) DN.
647 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
653 * actually we do not want to accept by default the DCE form,
654 * we do not want to auto-detect it
657 } else if ( LDAP_DN_LDAP( flags ) ) {
659 * if dn starts with '/' let's make it a DCE dn
661 if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
662 flags |= LDAP_DN_FORMAT_DCE;
668 for ( ; p[ 0 ]; p++ ) {
671 err = ldap_str2rdn( p, &newRDN, (char **) &p, flags );
672 if ( err != LDAP_SUCCESS ) {
677 * We expect a rdn separator
680 switch ( LDAP_DN_FORMAT( flags ) ) {
681 case LDAP_DN_FORMAT_LDAPV3:
682 if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
683 rc = LDAP_DECODING_ERROR;
688 case LDAP_DN_FORMAT_LDAP:
689 case LDAP_DN_FORMAT_LDAPV2:
690 if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
691 rc = LDAP_DECODING_ERROR;
696 case LDAP_DN_FORMAT_DCE:
697 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
698 rc = LDAP_DECODING_ERROR;
706 tmpDN[nrdns++] = newRDN;
710 * make the static RDN array dynamically rescalable
712 if ( nrdns == num_slots ) {
715 if ( tmpDN == tmpDN_ ) {
716 tmp = LDAP_MALLOC( num_slots * 2 * sizeof( LDAPRDN * ) );
721 AC_MEMCPY( tmp, tmpDN, num_slots * sizeof( LDAPRDN * ) );
724 tmp = LDAP_REALLOC( tmpDN, num_slots * 2 * sizeof( LDAPRDN * ) );
735 if ( p[ 0 ] == '\0' ) {
737 * the DN is over, phew
739 newDN = (LDAPDN *)LDAP_MALLOC( sizeof(LDAPDN) +
740 sizeof(LDAPRDN *) * (nrdns+1));
741 if ( newDN == NULL ) {
747 newDN[0] = (LDAPRDN **)(newDN+1);
749 if ( LDAP_DN_DCE( flags ) ) {
750 /* add in reversed order */
751 for ( i=0; i<nrdns; i++ )
752 newDN[0][i] = tmpDN[nrdns-1-i];
754 for ( i=0; i<nrdns; i++ )
755 newDN[0][i] = tmpDN[i];
757 newDN[0][nrdns] = NULL;
766 ldap_rdnfree( newRDN );
769 for ( nrdns-- ;nrdns >= 0; nrdns-- ) {
770 ldap_rdnfree( tmpDN[nrdns] );
775 if ( tmpDN != tmpDN_ ) {
779 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
788 * Parses a relative DN according to flags up to a rdn separator
789 * or to the end of str.
790 * Returns the rdn and a pointer to the string continuation, which
791 * corresponds to the rdn separator or to '\0' in case the string is over.
794 ldap_str2rdn( LDAP_CONST char *str, LDAPRDN **rdn,
795 char **n_in, unsigned flags )
797 const char **n = (const char **) n_in;
801 int rc = LDAP_DECODING_ERROR;
802 int attrTypeEncoding = LDAP_AVA_STRING,
803 attrValueEncoding = LDAP_AVA_STRING;
805 struct berval attrType = { 0, NULL };
806 struct berval attrValue = { 0, NULL };
808 LDAPRDN *newRDN = NULL;
809 LDAPAVA *tmpRDN_[TMP_AVA_SLOTS], **tmpRDN = tmpRDN_;
810 int num_slots = TMP_AVA_SLOTS;
813 assert( rdn || flags & LDAP_DN_SKIP );
817 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );
825 switch ( LDAP_DN_FORMAT( flags ) ) {
826 case LDAP_DN_FORMAT_LDAP:
827 case LDAP_DN_FORMAT_LDAPV3:
828 case LDAP_DN_FORMAT_LDAPV2:
829 case LDAP_DN_FORMAT_DCE:
832 /* unsupported in str2dn */
833 case LDAP_DN_FORMAT_UFN:
834 case LDAP_DN_FORMAT_AD_CANONICAL:
835 return LDAP_PARAM_ERROR;
837 case LDAP_DN_FORMAT_LBER:
839 return LDAP_PARAM_ERROR;
842 if ( str[ 0 ] == '\0' ) {
847 for ( ; p[ 0 ] || state == GOTAVA; ) {
850 * The parser in principle advances one token a time,
851 * or toggles state if preferable.
856 * an AttributeType can be encoded as:
857 * - its string representation; in detail, implementations
858 * MUST recognize AttributeType string type names listed
859 * in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
860 * MAY recognize other names.
861 * - its numeric OID (a dotted decimal string); in detail
862 * RFC 2253 asserts that ``Implementations MUST allow
863 * an oid in the attribute type to be prefixed by one
864 * of the character strings "oid." or "OID."''. As soon
865 * as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253
866 * I'm not sure whether this is required or not any
867 * longer; to be liberal, we still implement it.
870 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
871 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
878 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
879 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
884 /* whitespace is allowed (and trimmed) */
886 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
891 /* error: we expected an AVA */
897 if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
898 state = B4OIDATTRTYPE;
902 /* else must be alpha */
903 if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
907 /* LDAPv2 "oid." prefix */
908 if ( LDAP_DN_LDAPV2( flags ) ) {
910 * to be overly pedantic, we only accept
913 if ( flags & LDAP_DN_PEDANTIC ) {
914 if ( !strncmp( p, "OID.", 4 )
915 || !strncmp( p, "oid.", 4 ) ) {
917 state = B4OIDATTRTYPE;
921 if ( !strncasecmp( p, "oid.", 4 ) ) {
923 state = B4OIDATTRTYPE;
929 state = B4STRINGATTRTYPE;
932 case B4OIDATTRTYPE: {
933 int err = LDAP_SUCCESS;
935 attrType.bv_val = ldap_int_parse_numericoid( &p, &err,
938 if ( err != LDAP_SUCCESS ) {
941 attrType.bv_len = p - attrType.bv_val;
943 attrTypeEncoding = LDAP_AVA_BINARY;
949 case B4STRINGATTRTYPE: {
950 const char *startPos, *endPos = NULL;
954 * the starting char has been found to be
955 * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
956 * FIXME: DCE attr types seem to have a more
957 * restrictive syntax (no '-' ...)
959 for ( startPos = p++; p[ 0 ]; p++ ) {
960 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
964 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
967 * RFC 2253 does not explicitly
968 * allow lang extensions to attribute
971 if ( flags & LDAP_DN_PEDANTIC ) {
976 * we trim ';' and following lang
977 * and so from attribute types
980 for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
981 || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
989 len = ( endPos ? endPos : p ) - startPos;
994 attrTypeEncoding = LDAP_AVA_STRING;
997 * here we need to decide whether to use it as is
998 * or turn it in OID form; as a consequence, we
999 * need to decide whether to binary encode the value
1002 state = B4AVAEQUALS;
1004 if ( flags & LDAP_DN_SKIP ) {
1008 attrType.bv_val = (char *)startPos;
1009 attrType.bv_len = len;
1015 /* spaces may not be allowed */
1016 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1017 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1022 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1027 /* need equal sign */
1028 if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1033 /* spaces may not be allowed */
1034 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1035 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1040 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1046 * octothorpe means a BER encoded value will follow
1047 * FIXME: I don't think DCE will allow it
1049 if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1051 attrValueEncoding = LDAP_AVA_BINARY;
1052 state = B4BINARYVALUE;
1056 /* STRING value expected */
1059 * if we're pedantic, an attribute type in OID form
1060 * SHOULD imply a BER encoded attribute value; we
1061 * should at least issue a warning
1063 if ( ( flags & LDAP_DN_PEDANTIC )
1064 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1065 /* OID attrType SHOULD use binary encoding */
1069 attrValueEncoding = LDAP_AVA_STRING;
1072 * LDAPv2 allows the attribute value to be quoted;
1073 * also, IA5 values are expected, in principle
1075 if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1076 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1078 state = B4IA5VALUEQUOTED;
1082 if ( LDAP_DN_LDAPV2( flags ) ) {
1089 * here STRING means RFC 2253 string
1090 * FIXME: what about DCE strings?
1096 state = B4STRINGVALUE;
1101 if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
1109 switch ( LDAP_DN_FORMAT( flags ) ) {
1110 case LDAP_DN_FORMAT_LDAP:
1111 case LDAP_DN_FORMAT_LDAPV3:
1112 if ( str2strval( p, &attrValue, &p, flags,
1113 &attrValueEncoding ) ) {
1118 case LDAP_DN_FORMAT_DCE:
1119 if ( DCE2strval( p, &attrValue, &p, flags ) ) {
1132 if ( IA52strval( p, &attrValue, &p, flags ) ) {
1139 case B4IA5VALUEQUOTED:
1141 /* lead quote already stripped */
1142 if ( quotedIA52strval( p, &attrValue,
1153 if ( !( flags & LDAP_DN_SKIP ) ) {
1157 * we accept empty values
1159 ava = ldapava_new( &attrType, &attrValue,
1160 attrValueEncoding );
1162 if ( ava == NULL ) {
1163 rc = LDAP_NO_MEMORY;
1166 tmpRDN[navas++] = ava;
1168 attrValue.bv_val = NULL;
1169 attrValue.bv_len = 0;
1172 * prepare room for new AVAs if needed
1174 if (navas == num_slots) {
1177 if ( tmpRDN == tmpRDN_ ) {
1178 tmp = LDAP_MALLOC( num_slots * 2 * sizeof( LDAPAVA * ) );
1179 if ( tmp == NULL ) {
1180 rc = LDAP_NO_MEMORY;
1183 AC_MEMCPY( tmp, tmpRDN, num_slots * sizeof( LDAPAVA * ) );
1186 tmp = LDAP_REALLOC( tmpRDN, num_slots * 2 * sizeof( LDAPAVA * ) );
1187 if ( tmp == NULL ) {
1188 rc = LDAP_NO_MEMORY;
1199 * if we got an AVA separator ('+', or ',' for DCE )
1200 * we expect a new AVA for this RDN; otherwise
1201 * we add the RDN to the DN
1203 switch ( LDAP_DN_FORMAT( flags ) ) {
1204 case LDAP_DN_FORMAT_LDAP:
1205 case LDAP_DN_FORMAT_LDAPV3:
1206 case LDAP_DN_FORMAT_LDAPV2:
1207 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1212 case LDAP_DN_FORMAT_DCE:
1213 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1221 * the RDN is over, phew
1224 if ( !( flags & LDAP_DN_SKIP ) ) {
1225 newRDN = (LDAPRDN *)LDAP_MALLOC( sizeof(LDAPRDN)
1226 + sizeof(LDAPAVA *) * (navas+1) );
1227 if ( newRDN == NULL ) {
1228 rc = LDAP_NO_MEMORY;
1233 newRDN[0] = (LDAPAVA**)(newRDN+1);
1235 for (i=0; i<navas; i++)
1236 newRDN[0][i] = tmpRDN[i];
1237 newRDN[0][i] = NULL;
1245 /* they should have been used in an AVA */
1246 attrType.bv_val = NULL;
1247 attrValue.bv_val = NULL;
1262 /* They are set to NULL after they're used in an AVA */
1264 if ( attrValue.bv_val ) {
1265 free( attrValue.bv_val );
1268 for ( navas-- ; navas >= 0; navas-- ) {
1269 ldap_avafree( tmpRDN[navas] );
1274 if ( tmpRDN != tmpRDN_ ) {
1275 LDAP_FREE( tmpRDN );
1279 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n",
1291 * reads in a UTF-8 string value, unescaping stuff:
1292 * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1293 * '\' + HEXPAIR(p) -> unhex(p)
1296 str2strval( const char *str, struct berval *val, const char **next, unsigned flags, unsigned *retFlags )
1298 const char *p, *startPos, *endPos = NULL;
1299 ber_len_t len, escapes;
1307 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1308 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1310 if ( p[ 0 ] == '\0' ) {
1313 if ( LDAP_DN_MAYESCAPE( p[ 0 ] ) ) {
1318 if ( LDAP_DN_HEXPAIR( p ) ) {
1321 hexstr2bin( p, &c );
1324 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1327 * we assume the string is UTF-8
1329 *retFlags = LDAP_AVA_NONPRINTABLE;
1336 if ( LDAP_DN_PEDANTIC & flags ) {
1340 * we do not allow escaping
1341 * of chars that don't need
1342 * to and do not belong to
1347 } else if (!LDAP_DN_ASCII_PRINTABLE( p[ 0 ] ) ) {
1348 *retFlags = LDAP_AVA_NONPRINTABLE;
1350 } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) )
1351 || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1354 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1356 * FIXME: maybe we can add
1357 * escapes if not pedantic?
1364 * we do allow unescaped spaces at the end
1365 * of the value only in non-pedantic mode
1367 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1368 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1369 if ( flags & LDAP_DN_PEDANTIC ) {
1373 /* strip trailing (unescaped) spaces */
1374 for ( endPos = p - 1;
1375 endPos > startPos + 1 &&
1376 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1377 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1384 if ( flags & LDAP_DN_SKIP ) {
1389 * FIXME: test memory?
1391 len = ( endPos ? endPos : p ) - startPos - escapes;
1394 if ( escapes == 0 ) {
1395 val->bv_val = LDAP_STRNDUP( startPos, len );
1400 val->bv_val = LDAP_MALLOC( len + 1 );
1401 for ( s = 0, d = 0; d < len; ) {
1402 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1404 if ( LDAP_DN_MAYESCAPE( startPos[ s ] ) ) {
1405 val->bv_val[ d++ ] =
1408 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1411 hexstr2bin( &startPos[ s ], &c );
1412 val->bv_val[ d++ ] = c;
1416 /* we should never get here */
1421 val->bv_val[ d++ ] = startPos[ s++ ];
1425 val->bv_val[ d ] = '\0';
1433 DCE2strval( const char *str, struct berval *val, const char **next, unsigned flags )
1435 const char *p, *startPos, *endPos = NULL;
1436 ber_len_t len, escapes;
1444 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1445 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1447 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1454 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1459 * FIXME: can we accept anything else? I guess we need
1460 * to stop if a value is not legal
1465 * (unescaped) trailing spaces are trimmed must be silently ignored;
1468 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1469 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1470 if ( flags & LDAP_DN_PEDANTIC ) {
1474 /* strip trailing (unescaped) spaces */
1475 for ( endPos = p - 1;
1476 endPos > startPos + 1 &&
1477 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1478 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1485 if ( flags & LDAP_DN_SKIP ) {
1489 len = ( endPos ? endPos : p ) - startPos - escapes;
1491 if ( escapes == 0 ){
1492 val->bv_val = LDAP_STRNDUP( startPos, len );
1497 val->bv_val = LDAP_MALLOC( len + 1 );
1498 for ( s = 0, d = 0; d < len; ) {
1500 * This point is reached only if escapes
1501 * are properly used, so all we need to
1504 if ( LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1508 val->bv_val[ d++ ] = startPos[ s++ ];
1510 val->bv_val[ d ] = '\0';
1511 assert( strlen( val->bv_val ) == len );
1518 IA52strval( const char *str, struct berval *val, const char **next, unsigned flags )
1520 const char *p, *startPos, *endPos = NULL;
1521 ber_len_t len, escapes;
1533 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1534 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1536 if ( p[ 0 ] == '\0' ) {
1540 if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1541 && ( LDAP_DN_PEDANTIC & flags ) ) {
1546 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1551 * FIXME: can we accept anything else? I guess we need
1552 * to stop if a value is not legal
1556 /* strip trailing (unescaped) spaces */
1558 endPos > startPos + 1 &&
1559 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1560 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1566 if ( flags & LDAP_DN_SKIP ) {
1570 len = ( endPos ? endPos : p ) - startPos - escapes;
1572 if ( escapes == 0 ) {
1573 val->bv_val = LDAP_STRNDUP( startPos, len );
1578 val->bv_val = LDAP_MALLOC( len + 1 );
1579 for ( s = 0, d = 0; d < len; ) {
1580 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1583 val->bv_val[ d++ ] = startPos[ s++ ];
1585 val->bv_val[ d ] = '\0';
1586 assert( strlen( val->bv_val ) == len );
1593 quotedIA52strval( const char *str, struct berval *val, const char **next, unsigned flags )
1595 const char *p, *startPos, *endPos = NULL;
1597 unsigned escapes = 0;
1605 /* initial quote already eaten */
1606 for ( startPos = p = str; p[ 0 ]; p++ ) {
1608 * According to RFC 1779, the quoted value can
1609 * contain escaped as well as unescaped special values;
1610 * as a consequence we tolerate escaped values
1611 * (e.g. '"\,"' -> '\,') and escape unescaped specials
1612 * (e.g. '","' -> '\,').
1614 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1615 if ( p[ 1 ] == '\0' ) {
1620 if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1621 && ( LDAP_DN_PEDANTIC & flags ) ) {
1623 * do we allow to escape normal chars?
1624 * LDAPv2 does not allow any mechanism
1625 * for escaping chars with '\' and hex
1632 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1634 /* eat closing quotes */
1640 * FIXME: can we accept anything else? I guess we need
1641 * to stop if a value is not legal
1645 if ( endPos == NULL ) {
1649 /* Strip trailing (unescaped) spaces */
1650 for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1655 if ( flags & LDAP_DN_SKIP ) {
1659 len = endPos - startPos - escapes;
1662 if ( escapes == 0 ) {
1663 val->bv_val = LDAP_STRNDUP( startPos, len );
1668 val->bv_val = LDAP_MALLOC( len + 1 );
1671 for ( s = d = 0; d < len; ) {
1672 if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1675 val->bv_val[ d++ ] = str[ s++ ];
1677 val->bv_val[ d ] = '\0';
1678 assert( strlen( val->bv_val ) == len );
1685 hexstr2bin( const char *str, char *c )
1695 if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1699 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c1 ) ) {
1702 assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) );
1709 if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1713 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c2 ) ) {
1714 *c += c2 - 'A' + 10;
1716 assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) );
1717 *c += c2 - 'a' + 10;
1725 hexstr2binval( const char *str, struct berval *val, const char **next, unsigned flags )
1727 const char *p, *startPos, *endPos = NULL;
1737 for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1738 switch ( LDAP_DN_FORMAT( flags ) ) {
1739 case LDAP_DN_FORMAT_LDAPV3:
1740 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1745 case LDAP_DN_FORMAT_LDAP:
1746 case LDAP_DN_FORMAT_LDAPV2:
1747 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1752 case LDAP_DN_FORMAT_DCE:
1753 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1759 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1760 if ( flags & LDAP_DN_PEDANTIC ) {
1765 for ( ; p[ 0 ]; p++ ) {
1766 switch ( LDAP_DN_FORMAT( flags ) ) {
1767 case LDAP_DN_FORMAT_LDAPV3:
1768 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1773 case LDAP_DN_FORMAT_LDAP:
1774 case LDAP_DN_FORMAT_LDAPV2:
1775 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1780 case LDAP_DN_FORMAT_DCE:
1781 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1790 if ( !LDAP_DN_HEXPAIR( p ) ) {
1798 if ( flags & LDAP_DN_SKIP ) {
1802 len = ( ( endPos ? endPos : p ) - startPos ) / 2;
1804 assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
1807 val->bv_val = LDAP_MALLOC( len + 1 );
1808 if ( val->bv_val == NULL ) {
1809 return( LDAP_NO_MEMORY );
1812 for ( s = 0, d = 0; d < len; s += 2, d++ ) {
1815 hexstr2bin( &startPos[ s ], &c );
1817 val->bv_val[ d ] = c;
1820 val->bv_val[ d ] = '\0';
1826 * convert a byte in a hexadecimal pair
1829 byte2hexpair( const char *val, char *pair )
1831 static const char hexdig[] = "0123456789ABCDEF";
1837 * we assume the string has enough room for the hex encoding
1841 pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
1842 pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
1848 * convert a binary value in hexadecimal pairs
1851 binval2hexstr( struct berval *val, char *str )
1858 if ( val->bv_len == 0 ) {
1863 * we assume the string has enough room for the hex encoding
1867 for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
1868 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1875 * Length of the string representation, accounting for escaped hex
1879 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
1881 ber_len_t l, cl = 1;
1883 int escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3;
1884 #ifdef PRETTY_ESCAPE
1885 int escaped_ascii_len = LDAP_DN_IS_PRETTY( flags ) ? 2 : 3;
1886 #endif /* PRETTY_ESCAPE */
1892 if ( val->bv_len == 0 ) {
1896 for ( l = 0, p = val->bv_val; p < val->bv_val + val->bv_len; p += cl ) {
1901 if ( p[ 0 ] == '\0' ) {
1907 cl = LDAP_UTF8_CHARLEN2( p, cl );
1909 /* illegal utf-8 char! */
1912 } else if ( cl > 1 ) {
1915 for ( cnt = 1; cnt < cl; cnt++ ) {
1916 if ( ( p[ cnt ] & 0xc0 ) != 0x80 ) {
1920 l += escaped_byte_len * cl;
1922 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
1923 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1924 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
1925 #ifdef PRETTY_ESCAPE
1927 if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) {
1929 if ( LDAP_DN_WILLESCAPE_CHAR( p[ 0 ] ) ) {
1933 * there might be some chars we want
1934 * to escape in form of a couple
1935 * of hexdigits for optimization purposes
1940 l += escaped_ascii_len;
1942 #else /* ! PRETTY_ESCAPE */
1944 #endif /* ! PRETTY_ESCAPE */
1957 * convert to string representation, escaping with hex the UTF-8 stuff;
1958 * assume the destination has enough room for escaping
1961 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
1963 ber_len_t s, d, end;
1969 if ( val->bv_len == 0 ) {
1975 * we assume the string has enough room for the hex encoding
1978 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
1984 if ( val->bv_val[ s ] == '\0' ) {
1994 * The length was checked in strval2strlen();
1995 * LDAP_UTF8_CHARLEN() should suffice
1997 cl = LDAP_UTF8_CHARLEN2( &val->bv_val[ s ], cl );
2001 * there might be some chars we want to escape in form
2002 * of a couple of hexdigits for optimization purposes
2004 if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) )
2005 #ifdef PRETTY_ESCAPE
2007 || LDAP_DN_WILLESCAPE_HEX( flags, val->bv_val[ s ] )
2009 || LDAP_DN_WILLESCAPE_CHAR( val->bv_val[ s ] )
2011 #else /* ! PRETTY_ESCAPE */
2012 || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2013 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2014 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
2016 #endif /* ! PRETTY_ESCAPE */
2020 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2025 } else if ( cl > 1 ) {
2027 str[ d++ ] = val->bv_val[ s++ ];
2031 #ifdef PRETTY_ESCAPE
2032 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2033 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2034 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2036 if ( !LDAP_DN_IS_PRETTY( flags ) ) {
2037 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2043 #endif /* PRETTY_ESCAPE */
2044 str[ d++ ] = val->bv_val[ s++ ];
2054 * Length of the IA5 string representation (no UTF-8 allowed)
2057 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
2066 if ( val->bv_len == 0 ) {
2070 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2072 * Turn value into a binary encoded BER
2077 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2078 if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2079 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2080 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2095 * convert to string representation (np UTF-8)
2096 * assume the destination has enough room for escaping
2099 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2101 ber_len_t s, d, end;
2107 if ( val->bv_len == 0 ) {
2112 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2114 * Turn value into a binary encoded BER
2121 * we assume the string has enough room for the hex encoding
2125 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2126 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2127 || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2128 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2131 str[ d++ ] = val->bv_val[ s++ ];
2141 * Length of the (supposedly) DCE string representation,
2142 * accounting for escaped hex of UTF-8 chars
2145 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2154 if ( val->bv_len == 0 ) {
2158 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2160 * FIXME: Turn the value into a binary encoded BER?
2165 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2166 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2181 * convert to (supposedly) DCE string representation,
2182 * escaping with hex the UTF-8 stuff;
2183 * assume the destination has enough room for escaping
2186 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2194 if ( val->bv_len == 0 ) {
2199 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2201 * FIXME: Turn the value into a binary encoded BER?
2209 * we assume the string has enough room for the hex encoding
2213 for ( s = 0, d = 0; s < val->bv_len; ) {
2214 if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2217 str[ d++ ] = val->bv_val[ s++ ];
2227 * Length of the (supposedly) AD canonical string representation,
2228 * accounting for escaped hex of UTF-8 chars
2231 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2240 if ( val->bv_len == 0 ) {
2244 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2246 * FIXME: Turn the value into a binary encoded BER?
2251 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2252 if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2267 * convert to (supposedly) AD string representation,
2268 * escaping with hex the UTF-8 stuff;
2269 * assume the destination has enough room for escaping
2272 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2280 if ( val->bv_len == 0 ) {
2285 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2287 * FIXME: Turn the value into a binary encoded BER?
2295 * we assume the string has enough room for the hex encoding
2299 for ( s = 0, d = 0; s < val->bv_len; ) {
2300 if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2303 str[ d++ ] = val->bv_val[ s++ ];
2313 * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2314 * the first part of the AD representation of the DN is written in DNS
2315 * form, i.e. dot separated domain name components (as suggested
2316 * by Luke Howard, http://www.padl.com/~lukeh)
2319 dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN )
2322 int domain = 0, first = 1;
2323 ber_len_t l = 1; /* we move the null also */
2326 /* we are guaranteed there's enough memory in str */
2332 assert( *iRDN >= 0 );
2334 str = bv->bv_val + pos;
2336 for ( i = *iRDN; i >= 0; i-- ) {
2340 assert( dn[ 0 ][ i ] );
2343 assert( rdn[ 0 ][ 0 ] );
2344 ava = rdn[ 0 ][ 0 ];
2346 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2354 AC_MEMCPY( str, ava->la_value.bv_val,
2355 ava->la_value.bv_len + 1);
2356 l += ava->la_value.bv_len;
2359 AC_MEMCPY( str + ava->la_value.bv_len + 1, bv->bv_val + pos, l);
2360 AC_MEMCPY( str, ava->la_value.bv_val,
2361 ava->la_value.bv_len );
2362 str[ ava->la_value.bv_len ] = '.';
2363 l += ava->la_value.bv_len + 1;
2368 bv->bv_len = pos + l - 1;
2374 rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
2375 int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2382 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2383 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2385 /* len(type) + '=' + '+' | ',' */
2386 l += ava->la_attr.bv_len + 2;
2388 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2389 /* octothorpe + twice the length */
2390 l += 1 + 2 * ava->la_value.bv_len;
2394 unsigned f = flags | ava->la_flags;
2396 if ( ( *s2l )( &ava->la_value, f, &vl ) ) {
2409 rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
2410 int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2415 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2416 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2418 AC_MEMCPY( &str[ l ], ava->la_attr.bv_val,
2419 ava->la_attr.bv_len );
2420 l += ava->la_attr.bv_len;
2424 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2426 if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2429 l += 2 * ava->la_value.bv_len;
2433 unsigned f = flags | ava->la_flags;
2435 if ( ( *s2s )( &ava->la_value, &str[ l ], f, &vl ) ) {
2440 str[ l++ ] = ( rdn[ 0 ][ iAVA + 1 ] ? '+' : ',' );
2449 rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2456 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2457 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2459 /* len(type) + '=' + ',' | '/' */
2460 l += ava->la_attr.bv_len + 2;
2462 switch ( ava->la_flags ) {
2463 case LDAP_AVA_BINARY:
2464 /* octothorpe + twice the length */
2465 l += 1 + 2 * ava->la_value.bv_len;
2468 case LDAP_AVA_STRING: {
2470 unsigned f = flags | ava->la_flags;
2472 if ( strval2DCEstrlen( &ava->la_value, f, &vl ) ) {
2490 rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2495 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2496 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2501 str[ l++ ] = ( iAVA ? ',' : '/' );
2504 AC_MEMCPY( &str[ l ], ava->la_attr.bv_val,
2505 ava->la_attr.bv_len );
2506 l += ava->la_attr.bv_len;
2510 switch ( ava->la_flags ) {
2511 case LDAP_AVA_BINARY:
2513 if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2516 l += 2 * ava->la_value.bv_len;
2519 case LDAP_AVA_STRING: {
2521 unsigned f = flags | ava->la_flags;
2523 if ( strval2DCEstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2541 rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2551 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2552 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2555 l += ( rdn[ 0 ][ iAVA + 1 ] ? 3 : 2 );
2557 /* FIXME: are binary values allowed in UFN? */
2558 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2559 /* octothorpe + twice the value */
2560 l += 1 + 2 * ava->la_value.bv_len;
2564 unsigned f = flags | ava->la_flags;
2566 if ( strval2strlen( &ava->la_value, f, &vl ) ) {
2579 rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
2584 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2585 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2587 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2589 if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2592 l += 2 * ava->la_value.bv_len;
2596 unsigned f = flags | ava->la_flags;
2598 if ( strval2str( &ava->la_value, &str[ l ], f, &vl ) ) {
2604 if ( rdn[ 0 ][ iAVA + 1 ]) {
2605 AC_MEMCPY( &str[ l ], " + ", 3 );
2609 AC_MEMCPY( &str[ l ], ", ", 2 );
2620 rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2630 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2631 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2636 /* FIXME: are binary values allowed in UFN? */
2637 switch ( ava->la_flags ) {
2638 case LDAP_AVA_BINARY:
2639 /* octothorpe + twice the value */
2640 l += 1 + 2 * ava->la_value.bv_len;
2643 case LDAP_AVA_STRING: {
2645 unsigned f = flags | ava->la_flags;
2647 if ( strval2ADstrlen( &ava->la_value, f, &vl ) ) {
2665 rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2670 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2671 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2676 str[ l++ ] = ( iAVA ? ',' : '/' );
2679 switch ( ava->la_flags ) {
2680 case LDAP_AVA_BINARY:
2682 if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2685 l += 2 * ava->la_value.bv_len;
2688 case LDAP_AVA_STRING: {
2690 unsigned f = flags | ava->la_flags;
2692 if ( strval2ADstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2712 * Returns in str a string representation of rdn based on flags.
2713 * There is some duplication of code between this and ldap_dn2str;
2714 * this is wanted to reduce the allocation of temporary buffers.
2717 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2724 if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
2725 return LDAP_PARAM_ERROR;
2728 rc = ldap_rdn2bv( rdn, &bv, flags );
2734 ldap_rdn2bv( LDAPRDN *rdn, struct berval *bv, unsigned flags )
2744 if ( rdn == NULL ) {
2745 bv->bv_val = LDAP_STRDUP( "" );
2746 return( LDAP_SUCCESS );
2750 * This routine wastes "back" bytes at the end of the string
2753 switch ( LDAP_DN_FORMAT( flags ) ) {
2754 case LDAP_DN_FORMAT_LDAPV3:
2755 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2756 return LDAP_DECODING_ERROR;
2760 case LDAP_DN_FORMAT_LDAPV2:
2761 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2762 return LDAP_DECODING_ERROR;
2766 case LDAP_DN_FORMAT_UFN:
2767 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2768 return LDAP_DECODING_ERROR;
2772 case LDAP_DN_FORMAT_DCE:
2773 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2774 return LDAP_DECODING_ERROR;
2778 case LDAP_DN_FORMAT_AD_CANONICAL:
2779 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2780 return LDAP_DECODING_ERROR;
2785 return( LDAP_PARAM_ERROR );
2788 bv->bv_val = LDAP_MALLOC( l + 1 );
2790 switch ( LDAP_DN_FORMAT( flags ) ) {
2791 case LDAP_DN_FORMAT_LDAPV3:
2792 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2str );
2796 case LDAP_DN_FORMAT_LDAPV2:
2797 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2IA5str );
2801 case LDAP_DN_FORMAT_UFN:
2802 rc = rdn2UFNstr( rdn, bv->bv_val, flags, &l );
2806 case LDAP_DN_FORMAT_DCE:
2807 rc = rdn2DCEstr( rdn, bv->bv_val, flags, &l, 1 );
2811 case LDAP_DN_FORMAT_AD_CANONICAL:
2812 rc = rdn2ADstr( rdn, bv->bv_val, flags, &l, 1 );
2817 /* need at least one of the previous */
2818 return LDAP_PARAM_ERROR;
2822 ldap_memfree( bv->bv_val );
2826 bv->bv_len = l - back;
2827 bv->bv_val[ bv->bv_len ] = '\0';
2829 return LDAP_SUCCESS;
2833 * Very bulk implementation; many optimizations can be performed
2834 * - a NULL dn results in an empty string ""
2837 * a) what do we do if a UTF-8 string must be converted in LDAPv2?
2838 * we must encode it in binary form ('#' + HEXPAIRs)
2839 * b) does DCE/AD support UTF-8?
2840 * no clue; don't think so.
2841 * c) what do we do when binary values must be converted in UTF/DCE/AD?
2842 * use binary encoded BER
2844 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
2851 if((flags & LDAP_DN_FORMAT_MASK) == LDAP_DN_FORMAT_LBER) {
2852 return LDAP_PARAM_ERROR;
2855 rc = ldap_dn2bv( dn, &bv, flags );
2860 int ldap_dn2bv( LDAPDN *dn, struct berval *bv, unsigned flags )
2863 int rc = LDAP_ENCODING_ERROR;
2866 /* stringifying helpers for LDAPv3/LDAPv2 */
2867 int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2868 int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2874 Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2bv(%u)\n%s%s", flags, "", "" );
2877 * a null dn means an empty dn string
2878 * FIXME: better raise an error?
2881 bv->bv_val = LDAP_STRDUP( "" );
2882 return( LDAP_SUCCESS );
2885 switch ( LDAP_DN_FORMAT( flags ) ) {
2886 case LDAP_DN_FORMAT_LDAPV3:
2887 sv2l = strval2strlen;
2891 case LDAP_DN_FORMAT_LDAPV2:
2892 sv2l = strval2IA5strlen;
2893 sv2s = strval2IA5str;
2896 for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
2898 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
2900 if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
2901 goto return_results;
2907 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2908 rc = LDAP_NO_MEMORY;
2912 for ( l = 0, iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
2914 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
2916 if ( rdn2str( rdn, &bv->bv_val[ l ], flags,
2918 LDAP_FREE( bv->bv_val );
2920 goto return_results;
2928 * trim the last ',' (the allocated memory
2929 * is one byte longer than required)
2931 bv->bv_len = len - 1;
2932 bv->bv_val[ bv->bv_len ] = '\0';
2937 case LDAP_DN_FORMAT_UFN: {
2939 * FIXME: quoting from RFC 1781:
2941 To take a distinguished name, and generate a name of this format with
2942 attribute types omitted, the following steps are followed.
2944 1. If the first attribute is of type CommonName, the type may be
2947 2. If the last attribute is of type Country, the type may be
2950 3. If the last attribute is of type Country, the last
2951 Organisation attribute may have the type omitted.
2953 4. All attributes of type OrganisationalUnit may have the type
2954 omitted, unless they are after an Organisation attribute or
2955 the first attribute is of type OrganisationalUnit.
2957 * this should be the pedantic implementation.
2959 * Here the standard implementation reflects
2960 * the one historically provided by OpenLDAP
2961 * (and UMIch, I presume), with the variant
2962 * of spaces and plusses (' + ') separating
2965 * A non-standard but nice implementation could
2966 * be to turn the final "dc" attributes into a
2967 * dot-separated domain.
2969 * Other improvements could involve the use of
2970 * friendly country names and so.
2973 int leftmost_dc = -1;
2975 #endif /* DC_IN_UFN */
2977 for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
2979 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
2981 if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
2982 goto return_results;
2987 if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
2988 if ( leftmost_dc == -1 ) {
2994 #endif /* DC_IN_UFN */
2997 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2998 rc = LDAP_NO_MEMORY;
3003 if ( leftmost_dc == -1 ) {
3004 #endif /* DC_IN_UFN */
3005 for ( l = 0, iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
3007 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
3009 if ( rdn2UFNstr( rdn, &bv->bv_val[ l ],
3011 LDAP_FREE( bv->bv_val );
3013 goto return_results;
3019 * trim the last ', ' (the allocated memory
3020 * is two bytes longer than required)
3022 bv->bv_len = len - 2;
3023 bv->bv_val[ bv->bv_len ] = '\0';
3026 last_iRDN = iRDN - 1;
3028 for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
3030 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
3032 if ( rdn2UFNstr( rdn, &bv->bv_val[ l ],
3034 LDAP_FREE( bv->bv_val );
3036 goto return_results;
3041 if ( !dn2domain( dn, bv, l, &last_iRDN ) ) {
3042 LDAP_FREE( bv->bv_val );
3044 goto return_results;
3047 /* the string is correctly terminated by dn2domain */
3049 #endif /* DC_IN_UFN */
3055 case LDAP_DN_FORMAT_DCE:
3056 for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
3058 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
3060 if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
3061 goto return_results;
3067 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3068 rc = LDAP_NO_MEMORY;
3072 for ( l = 0; iRDN--; ) {
3074 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
3076 if ( rdn2DCEstr( rdn, &bv->bv_val[ l ], flags,
3078 LDAP_FREE( bv->bv_val );
3080 goto return_results;
3088 bv->bv_val[ bv->bv_len ] = '\0';
3093 case LDAP_DN_FORMAT_AD_CANONICAL: {
3095 * Sort of UFN for DCE DNs: a slash ('/') separated
3096 * global->local DN with no types; strictly speaking,
3097 * the naming context should be a domain, which is
3098 * written in DNS-style, e.g. dot-deparated.
3102 * "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3106 * "microsoft.com/People/Bill,Gates"
3108 for ( iRDN = 0, len = -1; dn[ 0 ][ iRDN ]; iRDN++ ) {
3110 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
3112 if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
3113 goto return_results;
3119 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3120 rc = LDAP_NO_MEMORY;
3125 if ( iRDN && dn2domain( dn, bv, 0, &iRDN ) ) {
3126 for ( l = bv->bv_len; iRDN >= 0 ; iRDN-- ) {
3128 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
3130 if ( rdn2ADstr( rdn, &bv->bv_val[ l ],
3131 flags, &rdnl, 0 ) ) {
3132 LDAP_FREE( bv->bv_val );
3134 goto return_results;
3143 * Strictly speaking, AD canonical requires
3144 * a DN to be in the form "..., dc=smtg",
3145 * i.e. terminated by a domain component
3147 if ( flags & LDAP_DN_PEDANTIC ) {
3148 LDAP_FREE( bv->bv_val );
3150 rc = LDAP_ENCODING_ERROR;
3154 for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3156 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
3158 if ( rdn2ADstr( rdn, &bv->bv_val[ l ],
3159 flags, &rdnl, first ) ) {
3160 LDAP_FREE( bv->bv_val );
3162 goto return_results;
3172 bv->bv_val[ bv->bv_len ] = '\0';
3178 return LDAP_PARAM_ERROR;
3181 Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2bv(%s,%u)=%d\n",
3182 bv->bv_val, flags, rc );