3 * Copyright 1998-2000 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>
24 /* extension to UFN that turns trailing "dc=value" rdns in DNS style,
25 * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */
27 /* #define PRETTY_ESCAPE */
29 static int dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout );
31 /* from libraries/libldap/schema.c */
32 extern char * parse_numericoid(const char **sp, int *code, const int flags);
34 /* parsing/printing routines */
35 static int str2strval( const char *str, struct berval **val,
36 const char **next, unsigned flags, unsigned *retFlags );
37 static int DCE2strval( const char *str, struct berval **val,
38 const char **next, unsigned flags );
39 static int IA52strval( const char *str, struct berval **val,
40 const char **next, unsigned flags );
41 static int quotedIA52strval( const char *str, struct berval **val,
42 const char **next, unsigned flags );
43 static int hexstr2binval( const char *str, struct berval **val,
44 const char **next, unsigned flags );
45 static int hexstr2bin( const char *str, char *c );
46 static int byte2hexpair( const char *val, char *pair );
47 static int binval2hexstr( struct berval *val, char *str );
48 static int strval2strlen( struct berval *val, unsigned flags,
50 static int strval2str( struct berval *val, char *str, unsigned flags,
52 static int strval2IA5strlen( struct berval *val, unsigned flags,
54 static int strval2IA5str( struct berval *val, char *str, unsigned flags,
56 static int strval2DCEstrlen( struct berval *val, unsigned flags,
58 static int strval2DCEstr( struct berval *val, char *str, unsigned flags,
60 static int strval2ADstrlen( struct berval *val, unsigned flags,
62 static int strval2ADstr( struct berval *val, char *str, unsigned flags,
64 static int dn2domain( LDAPDN *dn, char *str, int *iRDN );
67 static LDAPAVA * ldapava_new(
68 const struct berval *attr, const struct berval *val, unsigned flags );
69 static LDAPRDN * ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava );
70 static LDAPRDN * ldapava_insert_into_rdn(
71 LDAPRDN *rdn, LDAPAVA *ava, unsigned where );
72 static LDAPDN * ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn );
73 static LDAPDN * ldapava_insert_into_dn(
74 LDAPDN *dn, LDAPRDN *rdn, unsigned where );
76 /* Higher level helpers */
77 static int rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
78 int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
79 static int rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
80 int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
81 static int rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
82 static int rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len );
83 static int rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
84 static int rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flag, ber_len_t *len, int first );
85 static int rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
86 static int rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first );
89 * RFC 1823 ldap_get_dn
92 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
97 Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
99 if ( entry == NULL ) {
100 ld->ld_errno = LDAP_PARAM_ERROR;
104 tmp = *entry->lm_ber; /* struct copy */
105 if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
106 ld->ld_errno = LDAP_DECODING_ERROR;
114 * RFC 1823 ldap_dn2ufn
117 ldap_dn2ufn( LDAP_CONST char *dn )
121 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
123 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_UFN );
129 * RFC 1823 ldap_explode_dn
132 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
135 char **values = NULL;
137 unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
139 Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
141 if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP )
146 if( tmpDN == NULL ) {
147 values = LDAP_MALLOC( sizeof( char * ) );
148 if( values == NULL ) return NULL;
154 for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) {
155 char *str, **v = NULL;
157 ldap_rdn2str( tmpDN[ iRDN ][ 0 ], &str, flag );
159 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iRDN ) );
161 LBER_VFREE( values );
162 ldap_dnfree( tmpDN );
166 values[ iRDN ] = str;
169 values[ iRDN ] = NULL;
174 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
177 char **values = NULL;
181 notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
183 Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
186 * we only parse the first rdn
187 * FIXME: we prefer efficiency over checking if the _ENTIRE_
190 if ( ldap_str2rdn( rdn, &tmpRDN, &p, LDAP_DN_FORMAT_LDAP )
195 for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) {
196 ber_len_t l = 0, vl, al = 0;
197 char *str, **v = NULL;
198 LDAPAVA *ava = tmpRDN[ iAVA ][ 0 ];
200 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iAVA ) );
206 if ( ava->la_flags == LDAP_AVA_BINARY ) {
207 vl = 1 + 2 * ava->la_value->bv_len;
210 if ( strval2strlen( ava->la_value,
211 ava->la_flags, &vl ) ) {
217 al = ava->la_attr->bv_len;
218 l = vl + ava->la_attr->bv_len + 1;
220 str = LDAP_MALLOC( l + 1 );
221 AC_MEMCPY( str, ava->la_attr->bv_val,
222 ava->la_attr->bv_len );
227 str = LDAP_MALLOC( l + 1 );
230 if ( ava->la_flags == LDAP_AVA_BINARY ) {
232 if ( binval2hexstr( ava->la_value, &str[ al ] ) ) {
237 if ( strval2str( ava->la_value, &str[ al ],
238 ava->la_flags, &vl ) ) {
244 values[ iAVA ] = str;
246 values[ iAVA ] = NULL;
248 ldap_rdnfree( tmpRDN );
253 LBER_VFREE( values );
254 ldap_rdnfree( tmpRDN );
259 ldap_dn2dcedn( LDAP_CONST char *dn )
263 Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
265 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_DCE );
271 ldap_dcedn2dn( LDAP_CONST char *dce )
275 Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
277 ( void )dn2dn( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
283 ldap_dn2ad_canonical( LDAP_CONST char *dn )
287 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
289 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP,
290 &out, LDAP_DN_FORMAT_AD_CANONICAL );
296 ldap_dn_normalize( const char *in, unsigned iflags, char **out, unsigned oflags )
300 Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );
302 return dn2dn( in, iflags, out, oflags);
306 * helper that changes the string representation of dnin
307 * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
310 * LDAP_DN_FORMAT_LDAP (rfc 2253 and ldapbis liberal,
311 * plus some rfc 1779)
312 * LDAP_DN_FORMAT_LDAPV3 (rfc 2253 and ldapbis)
313 * LDAP_DN_FORMAT_LDAPV2 (rfc 1779)
314 * LDAP_DN_FORMAT_DCE (?)
316 * fout can be any of the above except
317 * LDAP_DN_FORMAT_LDAP
319 * LDAP_DN_FORMAT_UFN (rfc 1781, partial and with extensions)
320 * LDAP_DN_FORMAT_AD_CANONICAL (?)
323 dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout )
326 LDAPDN *tmpDN = NULL;
332 if ( dnin == NULL ) {
333 return( LDAP_SUCCESS );
336 rc = ldap_str2dn( dnin , &tmpDN, fin );
337 if ( rc != LDAP_SUCCESS ) {
341 rc = ldap_dn2str( tmpDN, dnout, fout );
343 ldap_dnfree( tmpDN );
351 /* #define B4ATTRTYPE 0x0001 */
352 #define B4OIDATTRTYPE 0x0002
353 #define B4STRINGATTRTYPE 0x0003
355 #define B4AVAEQUALS 0x0100
356 #define B4AVASEP 0x0200
357 #define B4RDNSEP 0x0300
358 #define GOTAVA 0x0400
360 #define B4ATTRVALUE 0x0010
361 #define B4STRINGVALUE 0x0020
362 #define B4IA5VALUEQUOTED 0x0030
363 #define B4IA5VALUE 0x0040
364 #define B4BINARYVALUE 0x0050
367 * Helpers (mostly from slap.h)
368 * c is assumed to Unicode in an ASCII compatible format (UTF-8)
369 * Macros assume "C" Locale (ASCII)
371 #define LDAP_DN_ASCII_SPACE(c) \
372 ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
373 #define LDAP_DN_ASCII_LOWER(c) ( (c) >= 'a' && (c) <= 'z' )
374 #define LDAP_DN_ASCII_UPPER(c) ( (c) >= 'A' && (c) <= 'Z' )
375 #define LDAP_DN_ASCII_ALPHA(c) \
376 ( LDAP_DN_ASCII_LOWER(c) || LDAP_DN_ASCII_UPPER(c) )
377 #define LDAP_DN_ASCII_DIGIT(c) ( (c) >= '0' && (c) <= '9' )
378 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) ( (c) >= 'a' && (c) <= 'f' )
379 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) ( (c) >= 'A' && (c) <= 'F' )
380 #define LDAP_DN_ASCII_HEXDIGIT(c) \
381 ( LDAP_DN_ASCII_DIGIT(c) \
382 || LDAP_DN_ASCII_LCASE_HEXALPHA(c) \
383 || LDAP_DN_ASCII_UCASE_HEXALPHA(c) )
384 #define LDAP_DN_ASCII_ALNUM(c) \
385 ( LDAP_DN_ASCII_ALPHA(c) || LDAP_DN_ASCII_DIGIT(c) )
386 #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' )
389 #define LDAP_DN_OID_LEADCHAR(c) ( LDAP_DN_ASCII_DIGIT(c) )
390 #define LDAP_DN_DESC_LEADCHAR(c) ( LDAP_DN_ASCII_ALPHA(c) )
391 #define LDAP_DN_DESC_CHAR(c) ( LDAP_DN_ASCII_ALNUM(c) || (c) == '-' )
392 #define LDAP_DN_LANG_SEP(c) ( (c) == ';' )
393 #define LDAP_DN_ATTRDESC_CHAR(c) \
394 ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
396 /* special symbols */
397 #define LDAP_DN_AVA_EQUALS(c) ( (c) == '=' )
398 #define LDAP_DN_AVA_SEP(c) ( (c) == '+' )
399 #define LDAP_DN_RDN_SEP(c) ( (c) == ',' )
400 #define LDAP_DN_RDN_SEP_V2(c) ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
401 #define LDAP_DN_OCTOTHORPE(c) ( (c) == '#' )
402 #define LDAP_DN_QUOTES(c) ( (c) == '\"' )
403 #define LDAP_DN_ESCAPE(c) ( (c) == '\\' )
404 #define LDAP_DN_VALUE_END(c) \
405 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
406 #define LDAP_DN_NE(c) \
407 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
408 || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
409 #define LDAP_DN_NEEDESCAPE(c) \
410 ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
411 #define LDAP_DN_NEEDESCAPE_LEAD(c) \
412 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) )
413 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
414 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
415 #define LDAP_DN_WILLESCAPE_CHAR(c) \
416 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) || LDAP_DN_ESCAPE(c) )
417 #define LDAP_DN_IS_PRETTY(f) ( (f) & LDAP_DN_PRETTY )
418 #define LDAP_DN_WILLESCAPE_HEX(f, c) \
419 ( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
422 #define LDAP_DN_VALUE_END_V2(c) \
423 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
425 #define LDAP_DN_V2_SPECIAL(c) \
426 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
427 || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
428 || LDAP_DN_OCTOTHORPE(c) )
429 #define LDAP_DN_V2_PAIR(c) \
430 ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
433 * DCE (mostly from Luke Howard and IBM implementation for AIX)
435 * From: "Application Development Guide - Directory Services" (FIXME: add link?)
436 * Here escapes and valid chars for GDS are considered; as soon as more
437 * specific info is found, the macros will be updated.
439 * Chars: 'a'-'z', 'A'-'Z', '0'-'9',
440 * '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
442 * Metachars: '/', ',', '=', '\'.
444 * the '\' is used to escape other metachars.
450 * Attribute types must start with alphabetic chars and can contain
451 * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
453 #define LDAP_DN_RDN_SEP_DCE(c) ( (c) == '/' )
454 #define LDAP_DN_AVA_SEP_DCE(c) ( (c) == ',' )
455 #define LDAP_DN_ESCAPE_DCE(c) ( LDAP_DN_ESCAPE(c) )
456 #define LDAP_DN_VALUE_END_DCE(c) \
457 ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
458 #define LDAP_DN_NEEDESCAPE_DCE(c) \
459 ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
462 #define LDAP_DN_RDN_SEP_AD(c) ( (c) == '/' )
463 #define LDAP_DN_ESCAPE_AD(c) ( LDAP_DN_ESCAPE(c) )
464 #define LDAP_DN_AVA_SEP_AD(c) ( (c) == ',' ) /* assume same as DCE */
465 #define LDAP_DN_VALUE_END_AD(c) \
466 ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
467 #define LDAP_DN_NEEDESCAPE_AD(c) \
468 ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
471 #define LDAP_DN_HEXPAIR(s) \
472 ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
473 /* better look at the AttributeDescription? */
475 /* FIXME: no composite rdn or non-"dc" types, right?
476 * (what about "dc" in OID form?) */
477 /* FIXME: we do not allow binary values in domain, right? */
478 /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
479 /* NOTE: don't use strcasecmp() as it is locale specific! */
480 #define LDAP_DC_ATTR "dc"
481 #define LDAP_DC_ATTRU "DC"
482 #define LDAP_DN_IS_RDN_DC( r ) \
483 ( (r) && (r)[0][0] && !(r)[1] \
484 && ((r)[0][0]->la_flags == LDAP_AVA_STRING) \
485 && ((r)[0][0]->la_attr->bv_len == 2) \
486 && (((r)[0][0]->la_attr->bv_val[0] == LDAP_DC_ATTR[0]) \
487 || ((r)[0][0]->la_attr->bv_val[0] == LDAP_DC_ATTRU[0])) \
488 && (((r)[0][0]->la_attr->bv_val[1] == LDAP_DC_ATTR[1]) \
489 || ((r)[0][0]->la_attr->bv_val[1] == LDAP_DC_ATTRU[1])))
491 /* Composite rules */
492 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
493 ( LDAP_DN_LDAPV2(f) \
494 || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
495 #define LDAP_DN_ALLOW_SPACES(f) \
496 ( LDAP_DN_LDAPV2(f) \
497 || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
498 #define LDAP_DN_LDAP(f) \
499 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
500 #define LDAP_DN_LDAPV3(f) \
501 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
502 #define LDAP_DN_LDAPV2(f) \
503 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
504 #define LDAP_DN_DCE(f) \
505 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
506 #define LDAP_DN_UFN(f) \
507 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
508 #define LDAP_DN_ADC(f) \
509 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
510 #define LDAP_DN_FORMAT(f) ( (f) & LDAP_DN_FORMAT_MASK )
513 * LDAPAVA helpers (will become part of the API for operations
514 * on structural representations of DNs).
517 ldapava_new( const struct berval *attr, const struct berval *val,
525 ava = LDAP_MALLOC( sizeof( LDAPAVA ) );
527 /* should we test it? */
532 ava->la_attr = ( struct berval * )attr;
533 ava->la_value = ( struct berval * )val;
534 ava->la_flags = flags;
536 ava->la_private = NULL;
542 ldap_avafree( LDAPAVA *ava )
547 /* ava's private must be freed by caller
548 * (at present let's skip this check because la_private
549 * basically holds static data) */
550 assert( ava->la_private == NULL );
553 ber_bvfree( ava->la_attr );
554 ber_bvfree( ava->la_value );
560 ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava )
568 for ( i = 0U; rdn[ i ]; i++ ) {
572 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
573 newRDN[ i ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
574 newRDN[ i ][ 0 ] = ava;
575 newRDN[ i + 1 ] = NULL;
581 ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where )
589 for ( i = 0U; rdn[ i ]; i++ ) {
595 /* assume "at end", which corresponds to
596 * ldapava_append_to_rdn */
599 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
601 /* data after insert point */
602 AC_MEMCPY( &newRDN[ where + 1 ], &newRDN[ where ],
603 ( i - where ) * sizeof( LDAPRDN * ) );
605 newRDN[ where ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
606 newRDN[ where ][ 0 ] = ava;
607 newRDN[ i + 1 ] = NULL;
613 ldap_rdnfree( LDAPRDN *rdn )
621 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
622 assert( rdn[ iAVA ][ 0 ] );
624 ldap_avafree( rdn[ iAVA ][ 0 ] );
631 ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn )
639 for ( i = 0U; dn[ i ]; i++ ) {
643 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
644 newDN[ i ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
645 newDN[ i ][ 0 ] = rdn;
646 newDN[ i + 1 ] = NULL;
652 ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where )
660 for ( i = 0U; dn[ i ]; i++ ) {
666 /* assume "at end", which corresponds to
667 * ldapava_append_to_dn */
670 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
672 /* data after insert point */
673 AC_MEMCPY( &newDN[ where + 1 ], &newDN[ where ],
674 ( i - where ) * sizeof( LDAPDN * ) );
676 newDN[ where ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
677 newDN[ where ][ 0 ] = rdn;
678 newDN[ i + 1 ] = NULL;
684 ldap_dnfree( LDAPDN *dn )
692 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
693 assert( dn[ iRDN ][ 0 ] );
695 ldap_rdnfree( dn[ iRDN ][ 0 ] );
702 * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
703 * into a structural representation of the DN, by separating attribute
704 * types and values encoded in the more appropriate form, which is
705 * string or OID for attribute types and binary form of the BER encoded
706 * value or Unicode string. Formats different from LDAPv3 are parsed
707 * according to their own rules and turned into the more appropriate
708 * form according to LDAPv3.
710 * NOTE: I realize the code is getting spaghettish; it is rather
711 * experimental and will hopefully turn into something more simple
712 * and readable as soon as it works as expected.
716 ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
719 int rc = LDAP_INVALID_DN_SYNTAX;
721 LDAPDN *newDN = NULL;
722 LDAPRDN *newRDN = NULL;
727 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );
731 switch ( LDAP_DN_FORMAT( flags ) ) {
732 case LDAP_DN_FORMAT_LDAP:
733 case LDAP_DN_FORMAT_LDAPV3:
734 case LDAP_DN_FORMAT_LDAPV2:
735 case LDAP_DN_FORMAT_DCE:
738 /* unsupported in str2dn */
739 case LDAP_DN_FORMAT_UFN:
740 case LDAP_DN_FORMAT_AD_CANONICAL:
741 return( LDAP_INVALID_DN_SYNTAX );
744 return( LDAP_OTHER );
747 if ( str[ 0 ] == '\0' ) {
748 return( LDAP_SUCCESS );
752 if ( LDAP_DN_DCE( flags ) ) {
755 * (from Luke Howard: thnx) A RDN separator is required
756 * at the beginning of an (absolute) DN.
758 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
763 } else if ( LDAP_DN_LDAP( flags ) ) {
765 * if dn starts with '/' let's make it a DCE dn
767 if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
768 flags |= LDAP_DN_FORMAT_DCE;
773 for ( ; p[ 0 ]; p++ ) {
777 err = ldap_str2rdn( p, &newRDN, &p, flags );
778 if ( err != LDAP_SUCCESS ) {
783 * We expect a rdn separator
786 switch ( LDAP_DN_FORMAT( flags ) ) {
787 case LDAP_DN_FORMAT_LDAPV3:
788 if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
794 case LDAP_DN_FORMAT_LDAP:
795 case LDAP_DN_FORMAT_LDAPV2:
796 if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
802 case LDAP_DN_FORMAT_DCE:
803 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
812 if ( LDAP_DN_DCE( flags ) ) {
813 /* add in reversed order */
814 dn = ldapava_insert_into_dn( newDN, newRDN, 0 );
816 dn = ldapava_append_to_dn( newDN, newRDN );
827 if ( p[ 0 ] == '\0' ) {
830 * the DN is over, phew
839 ldap_rdnfree( newRDN );
843 ldap_dnfree( newDN );
849 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
858 * Parses a relative DN according to flags up to a rdn separator
859 * or to the end of str.
860 * Returns the rdn and a pointer to the string continuation, which
861 * corresponds to the rdn separator or to '\0' in case the string is over.
864 ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
868 int rc = LDAP_INVALID_DN_SYNTAX;
869 int attrTypeEncoding = LDAP_AVA_STRING,
870 attrValueEncoding = LDAP_AVA_STRING;
872 struct berval *attrType = NULL;
873 struct berval *attrValue = NULL;
875 LDAPRDN *newRDN = NULL;
881 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );
886 switch ( LDAP_DN_FORMAT( flags ) ) {
887 case LDAP_DN_FORMAT_LDAP:
888 case LDAP_DN_FORMAT_LDAPV3:
889 case LDAP_DN_FORMAT_LDAPV2:
890 case LDAP_DN_FORMAT_DCE:
893 /* unsupported in str2dn */
894 case LDAP_DN_FORMAT_UFN:
895 case LDAP_DN_FORMAT_AD_CANONICAL:
896 return( LDAP_INVALID_DN_SYNTAX );
899 return( LDAP_OTHER );
902 if ( str[ 0 ] == '\0' ) {
903 return( LDAP_SUCCESS );
907 for ( ; p[ 0 ] || state == GOTAVA; ) {
910 * The parser in principle advances one token a time,
911 * or toggles state if preferable.
916 * an AttributeType can be encoded as:
917 * - its string representation; in detail, implementations
918 * MUST recognize AttributeType string type names listed
919 * in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
920 * MAY recognize other names.
921 * - its numeric OID (a dotted decimal string); in detail
922 * RFC 2253 asserts that ``Implementations MUST allow
923 * an oid in the attribute type to be prefixed by one
924 * of the character strings "oid." or "OID."''. As soon
925 * as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253
926 * I'm not sure whether this is required or not any
927 * longer; to be liberal, we still implement it.
930 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
931 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
938 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
939 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
944 /* whitespace is allowed (and trimmed) */
946 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
951 /* error: we expected an AVA */
957 if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
958 state = B4OIDATTRTYPE;
962 /* else must be alpha */
963 if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
967 /* LDAPv2 "oid." prefix */
968 if ( LDAP_DN_LDAPV2( flags ) ) {
970 * to be overly pedantic, we only accept
973 if ( flags & LDAP_DN_PEDANTIC ) {
974 if ( !strncmp( p, "OID.", 4 )
975 || !strncmp( p, "oid.", 4 ) ) {
977 state = B4OIDATTRTYPE;
981 if ( !strncasecmp( p, "oid.", 4 ) ) {
983 state = B4OIDATTRTYPE;
989 state = B4STRINGATTRTYPE;
992 case B4OIDATTRTYPE: {
993 int err = LDAP_SUCCESS;
996 type = parse_numericoid( &p, &err, 0 );
997 if ( type == NULL ) {
1000 attrType = LDAP_MALLOC( sizeof( struct berval ) );
1001 if ( attrType== NULL ) {
1002 rc = LDAP_NO_MEMORY;
1005 attrType->bv_val = type;
1006 attrType->bv_len = strlen( type );
1007 attrTypeEncoding = LDAP_AVA_BINARY;
1009 state = B4AVAEQUALS;
1013 case B4STRINGATTRTYPE: {
1014 const char *startPos, *endPos = NULL;
1018 * the starting char has been found to be
1019 * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
1020 * FIXME: DCE attr types seem to have a more
1021 * restrictive syntax (no '-' ...)
1023 for ( startPos = p++; p[ 0 ]; p++ ) {
1024 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
1028 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
1031 * RFC 2253 does not explicitly
1032 * allow lang extensions to attribute
1035 if ( flags & LDAP_DN_PEDANTIC ) {
1040 * we trim ';' and following lang
1041 * and so from attribute types
1044 for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
1045 || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
1053 len = ( endPos ? endPos : p ) - startPos;
1058 assert( attrType == NULL );
1059 attrType = LDAP_MALLOC( sizeof( struct berval ) );
1060 if ( attrType == NULL ) {
1061 rc = LDAP_NO_MEMORY;
1064 attrType->bv_val = LDAP_STRNDUP( startPos, len );
1065 if ( attrType->bv_val == NULL ) {
1066 rc = LDAP_NO_MEMORY;
1069 attrType->bv_len = len;
1070 attrTypeEncoding = LDAP_AVA_STRING;
1073 * here we need to decide whether to use it as is
1074 * or turn it in OID form; as a consequence, we
1075 * need to decide whether to binary encode the value
1078 state = B4AVAEQUALS;
1083 /* spaces may not be allowed */
1084 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1085 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1090 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1095 /* need equal sign */
1096 if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1101 /* spaces may not be allowed */
1102 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1103 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1108 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1114 * octothorpe means a BER encoded value will follow
1115 * FIXME: I don't think DCE will allow it
1117 if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1119 attrValueEncoding = LDAP_AVA_BINARY;
1120 state = B4BINARYVALUE;
1124 /* STRING value expected */
1127 * if we're pedantic, an attribute type in OID form
1128 * SHOULD imply a BER encoded attribute value; we
1129 * should at least issue a warning
1131 if ( ( flags & LDAP_DN_PEDANTIC )
1132 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1133 /* OID attrType SHOULD use binary encoding */
1137 attrValueEncoding = LDAP_AVA_STRING;
1140 * LDAPv2 allows the attribute value to be quoted;
1141 * also, IA5 values are expected, in principle
1143 if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1144 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1146 state = B4IA5VALUEQUOTED;
1150 if ( LDAP_DN_LDAPV2( flags ) ) {
1157 * here STRING means RFC 2253 string
1158 * FIXME: what about DCE strings?
1160 state = B4STRINGVALUE;
1164 if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
1172 switch ( LDAP_DN_FORMAT( flags ) ) {
1173 case LDAP_DN_FORMAT_LDAP:
1174 case LDAP_DN_FORMAT_LDAPV3:
1175 if ( str2strval( p, &attrValue, &p, flags,
1176 &attrValueEncoding ) ) {
1181 case LDAP_DN_FORMAT_DCE:
1182 if ( DCE2strval( p, &attrValue, &p, flags ) ) {
1195 if ( IA52strval( p, &attrValue, &p, flags ) ) {
1202 case B4IA5VALUEQUOTED:
1204 /* lead quote already stripped */
1205 if ( quotedIA52strval( p, &attrValue,
1219 * we accept empty values
1221 ava = ldapava_new( attrType, attrValue,
1222 attrValueEncoding );
1223 if ( ava == NULL ) {
1224 rc = LDAP_NO_MEMORY;
1228 rdn = ldapava_append_to_rdn( newRDN, ava );
1229 if ( rdn == NULL ) {
1230 rc = LDAP_NO_MEMORY;
1236 * if we got an AVA separator ('+', or ',' for DCE )
1237 * we expect a new AVA for this RDN; otherwise
1238 * we add the RDN to the DN
1240 switch ( LDAP_DN_FORMAT( flags ) ) {
1241 case LDAP_DN_FORMAT_LDAP:
1242 case LDAP_DN_FORMAT_LDAPV3:
1243 case LDAP_DN_FORMAT_LDAPV2:
1244 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1249 case LDAP_DN_FORMAT_DCE:
1250 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1258 * the RDN is over, phew
1265 /* they should have been used in an AVA */
1281 /* They are set to NULL after they're used in an AVA */
1283 ber_bvfree( attrType );
1287 ber_bvfree( attrValue );
1291 ldap_rdnfree( newRDN );
1297 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n",
1305 * reads in a UTF-8 string value, unescaping stuff:
1306 * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1307 * '\' + HEXPAIR(p) -> unhex(p)
1310 str2strval( const char *str, struct berval **val, const char **next, unsigned flags, unsigned *retFlags )
1312 const char *p, *startPos, *endPos = NULL;
1313 ber_len_t len, escapes, unescapes;
1322 for ( startPos = p = str, escapes = 0, unescapes = 0; p[ 0 ]; p++ ) {
1323 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1325 if ( p[ 0 ] == '\0' ) {
1328 if ( ( p == startPos + 1 && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1329 || ( LDAP_DN_VALUE_END( p[ 1 ] ) && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
1330 || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1335 if ( LDAP_DN_HEXPAIR( p ) ) {
1338 hexstr2bin( p, &c );
1341 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1344 * we assume the string is UTF-8
1346 *retFlags = LDAP_AVA_NONPRINTABLE;
1353 if ( LDAP_DN_PEDANTIC & flags ) {
1357 * FIXME: we allow escaping
1358 * of chars that don't need
1359 * to and do not belong to
1360 * HEXDIGITS (we also allow
1361 * single hexdigit; maybe we
1366 } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) )
1367 || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1370 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1372 * FIXME: maybe we can add
1373 * escapes if not pedantic?
1380 * we do allow unescaped spaces at the end
1381 * of the value only in non-pedantic mode
1383 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1384 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1385 if ( flags & LDAP_DN_PEDANTIC ) {
1389 /* strip trailing (unescaped) spaces */
1390 for ( endPos = p - 1;
1391 endPos > startPos + 1 &&
1392 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1393 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1400 * FIXME: test memory?
1402 len = ( endPos ? endPos : p ) - startPos - escapes - unescapes;
1403 *val = LDAP_MALLOC( sizeof( struct berval ) );
1404 ( *val )->bv_len = len;
1406 if ( escapes == 0 && unescapes == 0 ) {
1407 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1412 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1413 for ( s = 0, d = 0; d < len; ) {
1414 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1416 if ( ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( startPos[ s ] ) )
1417 || ( s == len - 1 && LDAP_DN_NEEDESCAPE_TRAIL( startPos[ s ] ) )
1418 || LDAP_DN_NEEDESCAPE( startPos[ s ] ) ) {
1419 ( *val )->bv_val[ d++ ] =
1422 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1425 hexstr2bin( &startPos[ s ], &c );
1426 ( *val )->bv_val[ d++ ] = c;
1431 * we allow escaping of chars
1432 * that do not need to
1434 ( *val )->bv_val[ d++ ] =
1439 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1443 ( *val )->bv_val[ d ] = '\0';
1444 assert( strlen( ( *val )->bv_val ) == len );
1454 DCE2strval( const char *str, struct berval **val, const char **next, unsigned flags )
1456 const char *p, *startPos, *endPos = NULL;
1457 ber_len_t len, escapes;
1466 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1467 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1469 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1476 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1481 * FIXME: can we accept anything else? I guess we need
1482 * to stop if a value is not legal
1487 * (unescaped) trailing spaces are trimmed must be silently ignored;
1490 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1491 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1492 if ( flags & LDAP_DN_PEDANTIC ) {
1496 /* strip trailing (unescaped) spaces */
1497 for ( endPos = p - 1;
1498 endPos > startPos + 1 &&
1499 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1500 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1507 len = ( endPos ? endPos : p ) - startPos - escapes;
1508 *val = LDAP_MALLOC( sizeof( struct berval ) );
1509 ( *val )->bv_len = len;
1510 if ( escapes == 0 ){
1511 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1516 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1517 for ( s = 0, d = 0; d < len; ) {
1519 * This point is reached only if escapes
1520 * are properly used, so all we need to
1523 if ( LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1527 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1529 ( *val )->bv_val[ d ] = '\0';
1530 assert( strlen( ( *val )->bv_val ) == len );
1539 IA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1541 const char *p, *startPos, *endPos = NULL;
1542 ber_len_t len, escapes;
1555 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1556 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1558 if ( p[ 0 ] == '\0' ) {
1562 if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1563 && ( LDAP_DN_PEDANTIC & flags ) ) {
1568 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1573 * FIXME: can we accept anything else? I guess we need
1574 * to stop if a value is not legal
1578 /* strip trailing (unescaped) spaces */
1580 endPos > startPos + 1 &&
1581 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1582 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1587 *val = LDAP_MALLOC( sizeof( struct berval ) );
1588 len = ( endPos ? endPos : p ) - startPos - escapes;
1589 ( *val )->bv_len = len;
1590 if ( escapes == 0 ) {
1591 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1596 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1597 for ( s = 0, d = 0; d < len; ) {
1598 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1601 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1603 ( *val )->bv_val[ d ] = '\0';
1604 assert( strlen( ( *val )->bv_val ) == len );
1612 quotedIA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1614 const char *p, *startPos, *endPos = NULL;
1616 unsigned escapes = 0;
1625 /* initial quote already eaten */
1626 for ( startPos = p = str; p[ 0 ]; p++ ) {
1628 * According to RFC 1779, the quoted value can
1629 * contain escaped as well as unescaped special values;
1630 * as a consequence we tolerate escaped values
1631 * (e.g. '"\,"' -> '\,') and escape unescaped specials
1632 * (e.g. '","' -> '\,').
1634 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1635 if ( p[ 1 ] == '\0' ) {
1640 if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1641 && ( LDAP_DN_PEDANTIC & flags ) ) {
1643 * do we allow to escape normal chars?
1644 * LDAPv2 does not allow any mechanism
1645 * for escaping chars with '\' and hex
1652 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1654 /* eat closing quotes */
1660 * FIXME: can we accept anything else? I guess we need
1661 * to stop if a value is not legal
1665 if ( endPos == NULL ) {
1669 /* Strip trailing (unescaped) spaces */
1670 for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1674 len = endPos - startPos - escapes;
1676 *val = LDAP_MALLOC( sizeof( struct berval ) );
1677 ( *val )->bv_len = len;
1678 if ( escapes == 0 ) {
1679 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1684 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1685 ( *val )->bv_len = len;
1687 for ( s = d = 0; d < len; ) {
1688 if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1691 ( *val )->bv_val[ d++ ] = str[ s++ ];
1693 ( *val )->bv_val[ d ] = '\0';
1694 assert( strlen( ( *val )->bv_val ) == len );
1703 hexstr2bin( const char *str, char *c )
1713 if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1719 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) ) {
1726 if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1732 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) ) {
1733 *c += c2 - 'a' + 10;
1741 hexstr2binval( const char *str, struct berval **val, const char **next, unsigned flags )
1743 const char *p, *startPos, *endPos = NULL;
1754 for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1755 switch ( LDAP_DN_FORMAT( flags ) ) {
1756 case LDAP_DN_FORMAT_LDAPV3:
1757 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1762 case LDAP_DN_FORMAT_LDAP:
1763 case LDAP_DN_FORMAT_LDAPV2:
1764 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1769 case LDAP_DN_FORMAT_DCE:
1770 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1776 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1777 if ( flags & LDAP_DN_PEDANTIC ) {
1782 for ( ; p[ 0 ]; p++ ) {
1783 switch ( LDAP_DN_FORMAT( flags ) ) {
1784 case LDAP_DN_FORMAT_LDAPV3:
1785 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1790 case LDAP_DN_FORMAT_LDAP:
1791 case LDAP_DN_FORMAT_LDAPV2:
1792 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1797 case LDAP_DN_FORMAT_DCE:
1798 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1807 if ( !LDAP_DN_HEXPAIR( p ) ) {
1814 len = ( ( endPos ? endPos : p ) - startPos ) / 2;
1816 assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
1818 *val = LDAP_MALLOC( sizeof( struct berval ) );
1819 if ( *val == NULL ) {
1820 return( LDAP_NO_MEMORY );
1823 ( *val )->bv_len = len;
1824 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1825 if ( ( *val )->bv_val == NULL ) {
1827 return( LDAP_NO_MEMORY );
1830 for ( s = 0, d = 0; d < len; s += 2, d++ ) {
1833 hexstr2bin( &startPos[ s ], &c );
1835 ( *val )->bv_val[ d ] = c;
1838 ( *val )->bv_val[ d ] = '\0';
1845 * convert a byte in a hexadecimal pair
1848 byte2hexpair( const char *val, char *pair )
1850 static const char hexdig[] = "0123456789ABCDEF";
1856 * we assume the string has enough room for the hex encoding
1860 pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
1861 pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
1867 * convert a binary value in hexadecimal pairs
1870 binval2hexstr( struct berval *val, char *str )
1877 if ( val->bv_len == 0 ) {
1882 * we assume the string has enough room for the hex encoding
1886 for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
1887 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1894 * Length of the string representation, accounting for escaped hex
1898 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
1900 ber_len_t l, cl = 1;
1902 int escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3;
1903 int escaped_ascii_len = LDAP_DN_IS_PRETTY( flags ) ? 2 : 3;
1909 if ( val->bv_len == 0 ) {
1913 for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
1914 cl = ldap_utf8_charlen( p );
1916 /* illegal utf-8 char! */
1919 } else if ( cl > 1 ) {
1922 for ( cnt = 1; cnt < cl; cnt++ ) {
1923 if ( ( p[ cnt ] & 0x80 ) == 0x00 ) {
1927 l += escaped_byte_len * cl;
1929 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
1930 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1931 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
1932 #ifdef PRETTY_ESCAPE
1933 if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) {
1936 * there might be some chars we want
1937 * to escape in form of a couple
1938 * of hexdigits for optimization purposes
1943 l += escaped_ascii_len;
1945 #else /* ! PRETTY_ESCAPE */
1947 #endif /* ! PRETTY_ESCAPE */
1960 * convert to string representation, escaping with hex the UTF-8 stuff;
1961 * assume the destination has enough room for escaping
1964 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
1966 ber_len_t s, d, end;
1972 if ( val->bv_len == 0 ) {
1978 * we assume the string has enough room for the hex encoding
1981 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
1982 ber_len_t cl = ldap_utf8_charlen( &val->bv_val[ s ] );
1985 * there might be some chars we want to escape in form
1986 * of a couple of hexdigits for optimization purposes
1988 if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) )
1989 #ifdef PRETTY_ESCAPE
1990 || LDAP_DN_WILLESCAPE_HEX( flags, val->bv_val[ s ] )
1991 #else /* ! PRETTY_ESCAPE */
1992 || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
1993 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
1994 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
1996 #endif /* ! PRETTY_ESCAPE */
2000 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2005 } else if ( cl > 1 ) {
2007 str[ d++ ] = val->bv_val[ s++ ];
2011 #ifdef PRETTY_ESCAPE
2012 if ( 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 if ( !LDAP_DN_IS_PRETTY( flags ) ) {
2017 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2023 #endif /* PRETTY_ESCAPE */
2024 str[ d++ ] = val->bv_val[ s++ ];
2034 * Length of the IA5 string representation (no UTF-8 allowed)
2037 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
2046 if ( val->bv_len == 0 ) {
2050 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2052 * Turn value into a binary encoded BER
2057 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2058 if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2059 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2060 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2075 * convert to string representation (np UTF-8)
2076 * assume the destination has enough room for escaping
2079 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2081 ber_len_t s, d, end;
2087 if ( val->bv_len == 0 ) {
2092 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2094 * Turn value into a binary encoded BER
2101 * we assume the string has enough room for the hex encoding
2105 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2106 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2107 || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2108 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2111 str[ d++ ] = val->bv_val[ s++ ];
2121 * Length of the (supposedly) DCE string representation,
2122 * accounting for escaped hex of UTF-8 chars
2125 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2134 if ( val->bv_len == 0 ) {
2138 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2140 * FIXME: Turn the value into a binary encoded BER?
2145 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2146 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2161 * convert to (supposedly) DCE string representation,
2162 * escaping with hex the UTF-8 stuff;
2163 * assume the destination has enough room for escaping
2166 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2174 if ( val->bv_len == 0 ) {
2179 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2181 * FIXME: Turn the value into a binary encoded BER?
2189 * we assume the string has enough room for the hex encoding
2193 for ( s = 0, d = 0; s < val->bv_len; ) {
2194 if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2197 str[ d++ ] = val->bv_val[ s++ ];
2207 * Length of the (supposedly) AD canonical string representation,
2208 * accounting for escaped hex of UTF-8 chars
2211 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2220 if ( val->bv_len == 0 ) {
2224 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2226 * FIXME: Turn the value into a binary encoded BER?
2231 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2232 if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2247 * convert to (supposedly) AD string representation,
2248 * escaping with hex the UTF-8 stuff;
2249 * assume the destination has enough room for escaping
2252 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2260 if ( val->bv_len == 0 ) {
2265 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2267 * FIXME: Turn the value into a binary encoded BER?
2275 * we assume the string has enough room for the hex encoding
2279 for ( s = 0, d = 0; s < val->bv_len; ) {
2280 if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2283 str[ d++ ] = val->bv_val[ s++ ];
2293 * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2294 * the forst part of the AD representation of the DN is written in DNS
2295 * form, i.e. dot separated domain name components (as suggested
2296 * by Luke Howard, http://www.padl.com/~lukeh)
2299 dn2domain( LDAPDN *dn, char *str, int *iRDN )
2302 int domain = 0, first = 1;
2303 ber_len_t l = 1; /* we move the null also */
2305 /* we are guaranteed there's enough memory in str */
2311 assert( *iRDN > 0 );
2313 for ( i = *iRDN; i >= 0; i-- ) {
2317 assert( dn[ i ][ 0 ] );
2320 assert( rdn[ 0 ][ 0 ] );
2321 ava = rdn[ 0 ][ 0 ];
2323 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2331 AC_MEMCPY( str, ava->la_value->bv_val,
2332 ava->la_value->bv_len + 1);
2333 l += ava->la_value->bv_len;
2336 AC_MEMCPY( str + ava->la_value->bv_len + 1, str, l);
2337 AC_MEMCPY( str, ava->la_value->bv_val,
2338 ava->la_value->bv_len );
2339 str[ ava->la_value->bv_len ] = '.';
2340 l += ava->la_value->bv_len + 1;
2350 rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
2351 int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2358 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2359 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2361 /* len(type) + '=' + '+' | ',' */
2362 l += ava->la_attr->bv_len + 2;
2364 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2365 /* octothorpe + twice the length */
2366 l += 1 + 2 * ava->la_value->bv_len;
2370 unsigned f = flags | ava->la_flags;
2372 if ( ( *s2l )( ava->la_value, f, &vl ) ) {
2385 rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
2386 int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2391 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2392 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2394 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2395 ava->la_attr->bv_len );
2396 l += ava->la_attr->bv_len;
2400 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2402 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2405 l += 2 * ava->la_value->bv_len;
2409 unsigned f = flags | ava->la_flags;
2411 if ( ( *s2s )( ava->la_value, &str[ l ], f, &vl ) ) {
2416 str[ l++ ] = ( rdn[ iAVA + 1 ] ? '+' : ',' );
2425 rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2432 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2433 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2435 /* len(type) + '=' + ',' | '/' */
2436 l += ava->la_attr->bv_len + 2;
2438 switch ( ava->la_flags ) {
2439 case LDAP_AVA_BINARY:
2440 /* octothorpe + twice the length */
2441 l += 1 + 2 * ava->la_value->bv_len;
2444 case LDAP_AVA_STRING: {
2446 unsigned f = flags | ava->la_flags;
2448 if ( strval2DCEstrlen( ava->la_value, f, &vl ) ) {
2466 rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2471 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2472 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2477 str[ l++ ] = ( iAVA ? ',' : '/' );
2480 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2481 ava->la_attr->bv_len );
2482 l += ava->la_attr->bv_len;
2486 switch ( ava->la_flags ) {
2487 case LDAP_AVA_BINARY:
2489 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2492 l += 2 * ava->la_value->bv_len;
2495 case LDAP_AVA_STRING: {
2497 unsigned f = flags | ava->la_flags;
2499 if ( strval2DCEstr( ava->la_value, &str[ l ], f, &vl ) ) {
2517 rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2527 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2528 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2531 l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
2533 /* FIXME: are binary values allowed in UFN? */
2534 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2535 /* octothorpe + twice the value */
2536 l += 1 + 2 * ava->la_value->bv_len;
2540 unsigned f = flags | ava->la_flags;
2542 if ( strval2strlen( ava->la_value, f, &vl ) ) {
2555 rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
2560 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2561 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2563 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2565 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2568 l += 2 * ava->la_value->bv_len;
2572 unsigned f = flags | ava->la_flags;
2574 if ( strval2str( ava->la_value, &str[ l ], f, &vl ) ) {
2580 if ( rdn[ iAVA + 1 ]) {
2581 AC_MEMCPY( &str[ l ], " + ", 3 );
2585 AC_MEMCPY( &str[ l ], ", ", 2 );
2596 rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2606 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2607 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2612 /* FIXME: are binary values allowed in UFN? */
2613 switch ( ava->la_flags ) {
2614 case LDAP_AVA_BINARY:
2615 /* octothorpe + twice the value */
2616 l += 1 + 2 * ava->la_value->bv_len;
2619 case LDAP_AVA_STRING: {
2621 unsigned f = flags | ava->la_flags;
2623 if ( strval2ADstrlen( ava->la_value, f, &vl ) ) {
2641 rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2646 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2647 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2652 str[ l++ ] = ( iAVA ? ',' : '/' );
2655 switch ( ava->la_flags ) {
2656 case LDAP_AVA_BINARY:
2658 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2661 l += 2 * ava->la_value->bv_len;
2664 case LDAP_AVA_STRING: {
2666 unsigned f = flags | ava->la_flags;
2668 if ( strval2ADstr( ava->la_value, &str[ l ], f, &vl ) ) {
2688 * Returns in str a string representation of rdn based on flags.
2689 * There is some duplication of code between this and ldap_dn2str;
2690 * this is wanted to reduce the allocation of temporary buffers.
2693 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2700 if ( rdn == NULL ) {
2701 *str = LDAP_STRDUP( "" );
2702 return( LDAP_SUCCESS );
2706 * This routine wastes "back" bytes at the end of the string
2710 switch ( LDAP_DN_FORMAT( flags ) ) {
2711 case LDAP_DN_FORMAT_LDAPV3:
2712 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2713 return( LDAP_OTHER );
2717 case LDAP_DN_FORMAT_LDAPV2:
2718 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2719 return( LDAP_OTHER );
2723 case LDAP_DN_FORMAT_UFN:
2724 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2725 return( LDAP_OTHER );
2729 case LDAP_DN_FORMAT_DCE:
2730 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2731 return( LDAP_OTHER );
2735 case LDAP_DN_FORMAT_AD_CANONICAL:
2736 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2737 return( LDAP_OTHER );
2742 return( LDAP_INVALID_DN_SYNTAX );
2745 *str = LDAP_MALLOC( l + 1 );
2747 switch ( LDAP_DN_FORMAT( flags ) ) {
2748 case LDAP_DN_FORMAT_LDAPV3:
2749 rc = rdn2str( rdn, *str, flags, &l, strval2str );
2753 case LDAP_DN_FORMAT_LDAPV2:
2754 rc = rdn2str( rdn, *str, flags, &l, strval2IA5str );
2758 case LDAP_DN_FORMAT_UFN:
2759 rc = rdn2UFNstr( rdn, *str, flags, &l );
2763 case LDAP_DN_FORMAT_DCE:
2764 rc = rdn2DCEstr( rdn, *str, flags, &l, 1 );
2768 case LDAP_DN_FORMAT_AD_CANONICAL:
2769 rc = rdn2ADstr( rdn, *str, flags, &l, 1 );
2774 /* need at least one of the previous */
2775 return( LDAP_OTHER );
2779 ldap_memfree( *str );
2780 return( LDAP_OTHER );
2783 ( *str )[ l - back ] = '\0';
2785 return( LDAP_SUCCESS );
2789 * Very bulk implementation; many optimizations can be performed
2790 * - a NULL dn results in an empty string ""
2793 * a) what do we do if a UTF-8 string must be converted in LDAPv2?
2794 * we must encode it in binary form ('#' + HEXPAIRs)
2795 * b) does DCE/AD support UTF-8?
2796 * no clue; don't think so.
2797 * c) what do we do when binary values must be converted in UTF/DCE/AD?
2798 * use binary encoded BER
2800 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
2803 int rc = LDAP_OTHER;
2806 /* stringifying helpers for LDAPv3/LDAPv2 */
2807 int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2808 int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2812 Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2str(%u)\n%s%s", flags, "", "" );
2817 * a null dn means an empty dn string
2818 * FIXME: better raise an error?
2821 *str = LDAP_STRDUP( "" );
2822 return( LDAP_SUCCESS );
2825 switch ( LDAP_DN_FORMAT( flags ) ) {
2826 case LDAP_DN_FORMAT_LDAPV3:
2827 sv2l = strval2strlen;
2831 case LDAP_DN_FORMAT_LDAPV2:
2832 sv2l = strval2IA5strlen;
2833 sv2s = strval2IA5str;
2836 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2838 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2840 if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
2841 goto return_results;
2847 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2848 rc = LDAP_NO_MEMORY;
2852 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
2854 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2856 if ( rdn2str( rdn, &( *str )[ l ], flags,
2860 goto return_results;
2868 * trim the last ',' (the allocated memory
2869 * is one byte longer than required)
2871 ( *str )[ len - 1 ] = '\0';
2876 case LDAP_DN_FORMAT_UFN: {
2879 * FIXME: quoting from RFC 1781:
2881 To take a distinguished name, and generate a name of this format with
2882 attribute types omitted, the following steps are followed.
2884 1. If the first attribute is of type CommonName, the type may be
2887 2. If the last attribute is of type Country, the type may be
2890 3. If the last attribute is of type Country, the last
2891 Organisation attribute may have the type omitted.
2893 4. All attributes of type OrganisationalUnit may have the type
2894 omitted, unless they are after an Organisation attribute or
2895 the first attribute is of type OrganisationalUnit.
2897 * this should be the pedantic implementation.
2899 * Here the standard implementation reflects
2900 * the one historically provided by OpenLDAP
2901 * (and UMIch, I presume), with the variant
2902 * of spaces and plusses (' + ') separating
2905 * A non-standard but nice implementation could
2906 * be to turn the final "dc" attributes into a
2907 * dot-separated domain.
2909 * Other improvements could involve the use of
2910 * friendly country names and so.
2913 int leftmost_dc = -1;
2915 #endif /* DC_IN_UFN */
2917 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2919 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2921 if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
2922 goto return_results;
2927 if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
2928 if ( leftmost_dc == -1 ) {
2934 #endif /* DC_IN_UFN */
2937 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2938 rc = LDAP_NO_MEMORY;
2943 if ( leftmost_dc == -1 ) {
2944 #endif /* DC_IN_UFN */
2945 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
2947 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2949 if ( rdn2UFNstr( rdn, &( *str )[ l ],
2953 goto return_results;
2959 * trim the last ', ' (the allocated memory
2960 * is two bytes longer than required)
2962 ( *str )[ len - 2 ] = '\0';
2965 last_iRDN = iRDN - 1;
2967 for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
2969 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2971 if ( rdn2UFNstr( rdn, &( *str )[ l ],
2975 goto return_results;
2980 if ( !dn2domain( dn, &( *str )[ l ], &last_iRDN ) ) {
2983 goto return_results;
2986 /* the string is correctly terminated by dn2domain */
2988 #endif /* DC_IN_UFN */
2994 case LDAP_DN_FORMAT_DCE:
2996 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2998 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3000 if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
3001 goto return_results;
3007 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3008 rc = LDAP_NO_MEMORY;
3012 for ( l = 0; iRDN--; ) {
3014 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3016 if ( rdn2DCEstr( rdn, &( *str )[ l ], flags,
3020 goto return_results;
3027 ( *str )[ len ] = '\0';
3032 case LDAP_DN_FORMAT_AD_CANONICAL: {
3035 * Sort of UFN for DCE DNs: a slash ('/') separated
3036 * global->local DN with no types; strictly speaking,
3037 * the naming context should be a domain, which is
3038 * written in DNS-style, e.g. dot-deparated.
3042 * "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3046 * "microsoft.com/People/Bill,Gates"
3048 for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
3050 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3052 if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
3053 goto return_results;
3059 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3060 rc = LDAP_NO_MEMORY;
3065 if ( iRDN && dn2domain( dn, *str, &iRDN ) ) {
3066 for ( l = strlen( *str ); iRDN >= 0 ; iRDN-- ) {
3068 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3070 if ( rdn2ADstr( rdn, &( *str )[ l ],
3071 flags, &rdnl, 0 ) ) {
3074 goto return_results;
3083 * Strictly speaking, AD canonical requires
3084 * a DN to be in the form "..., dc=smtg",
3085 * i.e. terminated by a domain component
3087 if ( flags & LDAP_DN_PEDANTIC ) {
3090 rc = LDAP_INVALID_DN_SYNTAX;
3094 for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3096 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3098 if ( rdn2ADstr( rdn, &( *str )[ l ],
3099 flags, &rdnl, first ) ) {
3102 goto return_results;
3111 ( *str )[ len ] = '\0';
3118 return( LDAP_INVALID_DN_SYNTAX );
3122 Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2str(%s,%u)=%d\n", *str, flags, rc );