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 Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
184 * we only parse the first rdn
185 * FIXME: we prefer efficiency over checking if the _ENTIRE_
188 if ( ldap_str2rdn( rdn, &tmpRDN, &p, LDAP_DN_FORMAT_LDAP )
193 for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) {
194 ber_len_t l = 0, vl, al = 0;
195 char *str, **v = NULL;
196 LDAPAVA *ava = tmpRDN[ iAVA ][ 0 ];
198 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iAVA ) );
204 if ( ava->la_flags == LDAP_AVA_BINARY ) {
205 vl = 1 + 2 * ava->la_value->bv_len;
208 if ( strval2strlen( ava->la_value,
209 ava->la_flags, &vl ) ) {
215 al = ava->la_attr->bv_len;
216 l = vl + ava->la_attr->bv_len + 1;
218 str = LDAP_MALLOC( l + 1 );
219 AC_MEMCPY( str, ava->la_attr->bv_val,
220 ava->la_attr->bv_len );
225 str = LDAP_MALLOC( l + 1 );
228 if ( ava->la_flags == LDAP_AVA_BINARY ) {
230 if ( binval2hexstr( ava->la_value, &str[ al ] ) ) {
235 if ( strval2str( ava->la_value, &str[ al ],
236 ava->la_flags, &vl ) ) {
242 values[ iAVA ] = str;
244 values[ iAVA ] = NULL;
246 ldap_rdnfree( tmpRDN );
251 LBER_VFREE( values );
252 ldap_rdnfree( tmpRDN );
257 ldap_dn2dcedn( LDAP_CONST char *dn )
261 Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
263 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_DCE );
269 ldap_dcedn2dn( LDAP_CONST char *dce )
273 Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
275 ( void )dn2dn( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
281 ldap_dn2ad_canonical( LDAP_CONST char *dn )
285 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
287 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP,
288 &out, LDAP_DN_FORMAT_AD_CANONICAL );
294 ldap_dn_normalize( const char *in, unsigned iflags, char **out, unsigned oflags )
298 Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );
300 return dn2dn( in, iflags, out, oflags);
304 * helper that changes the string representation of dnin
305 * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
308 * LDAP_DN_FORMAT_LDAP (rfc 2253 and ldapbis liberal,
309 * plus some rfc 1779)
310 * LDAP_DN_FORMAT_LDAPV3 (rfc 2253 and ldapbis)
311 * LDAP_DN_FORMAT_LDAPV2 (rfc 1779)
312 * LDAP_DN_FORMAT_DCE (?)
314 * fout can be any of the above except
315 * LDAP_DN_FORMAT_LDAP
317 * LDAP_DN_FORMAT_UFN (rfc 1781, partial and with extensions)
318 * LDAP_DN_FORMAT_AD_CANONICAL (?)
321 dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout )
324 LDAPDN *tmpDN = NULL;
330 if ( dnin == NULL ) {
331 return( LDAP_SUCCESS );
334 rc = ldap_str2dn( dnin , &tmpDN, fin );
335 if ( rc != LDAP_SUCCESS ) {
339 rc = ldap_dn2str( tmpDN, dnout, fout );
341 ldap_dnfree( tmpDN );
349 /* #define B4ATTRTYPE 0x0001 */
350 #define B4OIDATTRTYPE 0x0002
351 #define B4STRINGATTRTYPE 0x0003
353 #define B4AVAEQUALS 0x0100
354 #define B4AVASEP 0x0200
355 #define B4RDNSEP 0x0300
356 #define GOTAVA 0x0400
358 #define B4ATTRVALUE 0x0010
359 #define B4STRINGVALUE 0x0020
360 #define B4IA5VALUEQUOTED 0x0030
361 #define B4IA5VALUE 0x0040
362 #define B4BINARYVALUE 0x0050
365 * Helpers (mostly from slap.h)
366 * c is assumed to Unicode in an ASCII compatible format (UTF-8)
367 * Macros assume "C" Locale (ASCII)
369 #define LDAP_DN_ASCII_SPACE(c) \
370 ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
371 #define LDAP_DN_ASCII_LOWER(c) ( (c) >= 'a' && (c) <= 'z' )
372 #define LDAP_DN_ASCII_UPPER(c) ( (c) >= 'A' && (c) <= 'Z' )
373 #define LDAP_DN_ASCII_ALPHA(c) \
374 ( LDAP_DN_ASCII_LOWER(c) || LDAP_DN_ASCII_UPPER(c) )
375 #define LDAP_DN_ASCII_DIGIT(c) ( (c) >= '0' && (c) <= '9' )
376 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) ( (c) >= 'a' && (c) <= 'f' )
377 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) ( (c) >= 'A' && (c) <= 'F' )
378 #define LDAP_DN_ASCII_HEXDIGIT(c) \
379 ( LDAP_DN_ASCII_DIGIT(c) \
380 || LDAP_DN_ASCII_LCASE_HEXALPHA(c) \
381 || LDAP_DN_ASCII_UCASE_HEXALPHA(c) )
382 #define LDAP_DN_ASCII_ALNUM(c) \
383 ( LDAP_DN_ASCII_ALPHA(c) || LDAP_DN_ASCII_DIGIT(c) )
384 #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' )
387 #define LDAP_DN_OID_LEADCHAR(c) ( LDAP_DN_ASCII_DIGIT(c) )
388 #define LDAP_DN_DESC_LEADCHAR(c) ( LDAP_DN_ASCII_ALPHA(c) )
389 #define LDAP_DN_DESC_CHAR(c) ( LDAP_DN_ASCII_ALNUM(c) || (c) == '-' )
390 #define LDAP_DN_LANG_SEP(c) ( (c) == ';' )
391 #define LDAP_DN_ATTRDESC_CHAR(c) \
392 ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
394 /* special symbols */
395 #define LDAP_DN_AVA_EQUALS(c) ( (c) == '=' )
396 #define LDAP_DN_AVA_SEP(c) ( (c) == '+' )
397 #define LDAP_DN_RDN_SEP(c) ( (c) == ',' )
398 #define LDAP_DN_RDN_SEP_V2(c) ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
399 #define LDAP_DN_OCTOTHORPE(c) ( (c) == '#' )
400 #define LDAP_DN_QUOTES(c) ( (c) == '\"' )
401 #define LDAP_DN_ESCAPE(c) ( (c) == '\\' )
402 #define LDAP_DN_VALUE_END(c) \
403 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
404 #define LDAP_DN_NE(c) \
405 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
406 || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
407 #define LDAP_DN_NEEDESCAPE(c) \
408 ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
409 #define LDAP_DN_NEEDESCAPE_LEAD(c) \
410 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) )
411 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
412 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
413 #define LDAP_DN_WILLESCAPE_CHAR(c) \
414 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) || LDAP_DN_ESCAPE(c) )
415 #define LDAP_DN_IS_PRETTY(f) ( (f) & LDAP_DN_PRETTY )
416 #define LDAP_DN_WILLESCAPE_HEX(f, c) \
417 ( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
420 #define LDAP_DN_VALUE_END_V2(c) \
421 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
423 #define LDAP_DN_V2_SPECIAL(c) \
424 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
425 || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
426 || LDAP_DN_OCTOTHORPE(c) )
427 #define LDAP_DN_V2_PAIR(c) \
428 ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
431 * DCE (mostly from Luke Howard and IBM implementation for AIX)
433 * From: "Application Development Guide - Directory Services" (FIXME: add link?)
434 * Here escapes and valid chars for GDS are considered; as soon as more
435 * specific info is found, the macros will be updated.
437 * Chars: 'a'-'z', 'A'-'Z', '0'-'9',
438 * '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
440 * Metachars: '/', ',', '=', '\'.
442 * the '\' is used to escape other metachars.
448 * Attribute types must start with alphabetic chars and can contain
449 * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
451 #define LDAP_DN_RDN_SEP_DCE(c) ( (c) == '/' )
452 #define LDAP_DN_AVA_SEP_DCE(c) ( (c) == ',' )
453 #define LDAP_DN_ESCAPE_DCE(c) ( LDAP_DN_ESCAPE(c) )
454 #define LDAP_DN_VALUE_END_DCE(c) \
455 ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
456 #define LDAP_DN_NEEDESCAPE_DCE(c) \
457 ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
460 #define LDAP_DN_RDN_SEP_AD(c) ( (c) == '/' )
461 #define LDAP_DN_ESCAPE_AD(c) ( LDAP_DN_ESCAPE(c) )
462 #define LDAP_DN_AVA_SEP_AD(c) ( (c) == ',' ) /* assume same as DCE */
463 #define LDAP_DN_VALUE_END_AD(c) \
464 ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
465 #define LDAP_DN_NEEDESCAPE_AD(c) \
466 ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
469 #define LDAP_DN_HEXPAIR(s) \
470 ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
471 /* better look at the AttributeDescription? */
473 /* FIXME: no composite rdn or non-"dc" types, right?
474 * (what about "dc" in OID form?) */
475 /* FIXME: we do not allow binary values in domain, right? */
476 /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
477 /* NOTE: don't use strcasecmp() as it is locale specific! */
478 #define LDAP_DC_ATTR "dc"
479 #define LDAP_DC_ATTRU "DC"
480 #define LDAP_DN_IS_RDN_DC( r ) \
481 ( (r) && (r)[0][0] && !(r)[1] \
482 && ((r)[0][0]->la_flags == LDAP_AVA_STRING) \
483 && ((r)[0][0]->la_attr->bv_len == 2) \
484 && (((r)[0][0]->la_attr->bv_val[0] == LDAP_DC_ATTR[0]) \
485 || ((r)[0][0]->la_attr->bv_val[0] == LDAP_DC_ATTRU[0])) \
486 && (((r)[0][0]->la_attr->bv_val[1] == LDAP_DC_ATTR[1]) \
487 || ((r)[0][0]->la_attr->bv_val[1] == LDAP_DC_ATTRU[1])))
489 /* Composite rules */
490 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
491 ( LDAP_DN_LDAPV2(f) \
492 || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
493 #define LDAP_DN_ALLOW_SPACES(f) \
494 ( LDAP_DN_LDAPV2(f) \
495 || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
496 #define LDAP_DN_LDAP(f) \
497 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
498 #define LDAP_DN_LDAPV3(f) \
499 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
500 #define LDAP_DN_LDAPV2(f) \
501 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
502 #define LDAP_DN_DCE(f) \
503 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
504 #define LDAP_DN_UFN(f) \
505 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
506 #define LDAP_DN_ADC(f) \
507 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
508 #define LDAP_DN_FORMAT(f) ( (f) & LDAP_DN_FORMAT_MASK )
511 * LDAPAVA helpers (will become part of the API for operations
512 * on structural representations of DNs).
515 ldapava_new( const struct berval *attr, const struct berval *val,
523 ava = LDAP_MALLOC( sizeof( LDAPAVA ) );
525 /* should we test it? */
530 ava->la_attr = ( struct berval * )attr;
531 ava->la_value = ( struct berval * )val;
532 ava->la_flags = flags;
534 ava->la_private = NULL;
540 ldap_avafree( LDAPAVA *ava )
545 /* ava's private must be freed by caller
546 * (at present let's skip this check because la_private
547 * basically holds static data) */
548 assert( ava->la_private == NULL );
551 ber_bvfree( ava->la_attr );
552 ber_bvfree( ava->la_value );
558 ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava )
566 for ( i = 0U; rdn[ i ]; i++ ) {
570 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
571 newRDN[ i ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
572 newRDN[ i ][ 0 ] = ava;
573 newRDN[ i + 1 ] = NULL;
579 ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where )
587 for ( i = 0U; rdn[ i ]; i++ ) {
593 /* assume "at end", which corresponds to
594 * ldapava_append_to_rdn */
597 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
599 /* data after insert point */
600 AC_MEMCPY( &newRDN[ where + 1 ], &newRDN[ where ],
601 ( i - where ) * sizeof( LDAPRDN * ) );
603 newRDN[ where ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
604 newRDN[ where ][ 0 ] = ava;
605 newRDN[ i + 1 ] = NULL;
611 ldap_rdnfree( LDAPRDN *rdn )
619 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
620 assert( rdn[ iAVA ][ 0 ] );
622 ldap_avafree( rdn[ iAVA ][ 0 ] );
629 ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn )
637 for ( i = 0U; dn[ i ]; i++ ) {
641 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
642 newDN[ i ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
643 newDN[ i ][ 0 ] = rdn;
644 newDN[ i + 1 ] = NULL;
650 ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where )
658 for ( i = 0U; dn[ i ]; i++ ) {
664 /* assume "at end", which corresponds to
665 * ldapava_append_to_dn */
668 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
670 /* data after insert point */
671 AC_MEMCPY( &newDN[ where + 1 ], &newDN[ where ],
672 ( i - where ) * sizeof( LDAPDN * ) );
674 newDN[ where ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
675 newDN[ where ][ 0 ] = rdn;
676 newDN[ i + 1 ] = NULL;
682 ldap_dnfree( LDAPDN *dn )
690 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
691 assert( dn[ iRDN ][ 0 ] );
693 ldap_rdnfree( dn[ iRDN ][ 0 ] );
700 * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
701 * into a structural representation of the DN, by separating attribute
702 * types and values encoded in the more appropriate form, which is
703 * string or OID for attribute types and binary form of the BER encoded
704 * value or Unicode string. Formats different from LDAPv3 are parsed
705 * according to their own rules and turned into the more appropriate
706 * form according to LDAPv3.
708 * NOTE: I realize the code is getting spaghettish; it is rather
709 * experimental and will hopefully turn into something more simple
710 * and readable as soon as it works as expected.
714 ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
717 int rc = LDAP_INVALID_DN_SYNTAX;
719 LDAPDN *newDN = NULL;
720 LDAPRDN *newRDN = NULL;
725 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );
729 switch ( LDAP_DN_FORMAT( flags ) ) {
730 case LDAP_DN_FORMAT_LDAP:
731 case LDAP_DN_FORMAT_LDAPV3:
732 case LDAP_DN_FORMAT_LDAPV2:
733 case LDAP_DN_FORMAT_DCE:
736 /* unsupported in str2dn */
737 case LDAP_DN_FORMAT_UFN:
738 case LDAP_DN_FORMAT_AD_CANONICAL:
739 return( LDAP_INVALID_DN_SYNTAX );
742 return( LDAP_OTHER );
745 if ( str[ 0 ] == '\0' ) {
746 return( LDAP_SUCCESS );
750 if ( LDAP_DN_DCE( flags ) ) {
753 * (from Luke Howard: thnx) A RDN separator is required
754 * at the beginning of an (absolute) DN.
756 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
761 } else if ( LDAP_DN_LDAP( flags ) ) {
763 * if dn starts with '/' let's make it a DCE dn
765 if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
766 flags |= LDAP_DN_FORMAT_DCE;
771 for ( ; p[ 0 ]; p++ ) {
775 err = ldap_str2rdn( p, &newRDN, &p, flags );
776 if ( err != LDAP_SUCCESS ) {
781 * We expect a rdn separator
784 switch ( LDAP_DN_FORMAT( flags ) ) {
785 case LDAP_DN_FORMAT_LDAPV3:
786 if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
792 case LDAP_DN_FORMAT_LDAP:
793 case LDAP_DN_FORMAT_LDAPV2:
794 if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
800 case LDAP_DN_FORMAT_DCE:
801 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
810 if ( LDAP_DN_DCE( flags ) ) {
811 /* add in reversed order */
812 dn = ldapava_insert_into_dn( newDN, newRDN, 0 );
814 dn = ldapava_append_to_dn( newDN, newRDN );
825 if ( p[ 0 ] == '\0' ) {
828 * the DN is over, phew
837 ldap_rdnfree( newRDN );
841 ldap_dnfree( newDN );
847 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
856 * Parses a relative DN according to flags up to a rdn separator
857 * or to the end of str.
858 * Returns the rdn and a pointer to the string continuation, which
859 * corresponds to the rdn separator or to '\0' in case the string is over.
862 ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
866 int rc = LDAP_INVALID_DN_SYNTAX;
867 int attrTypeEncoding = LDAP_AVA_STRING,
868 attrValueEncoding = LDAP_AVA_STRING;
870 struct berval *attrType = NULL;
871 struct berval *attrValue = NULL;
873 LDAPRDN *newRDN = NULL;
879 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );
884 switch ( LDAP_DN_FORMAT( flags ) ) {
885 case LDAP_DN_FORMAT_LDAP:
886 case LDAP_DN_FORMAT_LDAPV3:
887 case LDAP_DN_FORMAT_LDAPV2:
888 case LDAP_DN_FORMAT_DCE:
891 /* unsupported in str2dn */
892 case LDAP_DN_FORMAT_UFN:
893 case LDAP_DN_FORMAT_AD_CANONICAL:
894 return( LDAP_INVALID_DN_SYNTAX );
897 return( LDAP_OTHER );
900 if ( str[ 0 ] == '\0' ) {
901 return( LDAP_SUCCESS );
905 for ( ; p[ 0 ] || state == GOTAVA; ) {
908 * The parser in principle advances one token a time,
909 * or toggles state if preferable.
914 * an AttributeType can be encoded as:
915 * - its string representation; in detail, implementations
916 * MUST recognize AttributeType string type names listed
917 * in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
918 * MAY recognize other names.
919 * - its numeric OID (a dotted decimal string); in detail
920 * RFC 2253 asserts that ``Implementations MUST allow
921 * an oid in the attribute type to be prefixed by one
922 * of the character strings "oid." or "OID."''. As soon
923 * as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253
924 * I'm not sure whether this is required or not any
925 * longer; to be liberal, we still implement it.
928 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
929 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
936 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
937 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
942 /* whitespace is allowed (and trimmed) */
944 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
949 /* error: we expected an AVA */
955 if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
956 state = B4OIDATTRTYPE;
960 /* else must be alpha */
961 if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
965 /* LDAPv2 "oid." prefix */
966 if ( LDAP_DN_LDAPV2( flags ) ) {
968 * to be overly pedantic, we only accept
971 if ( flags & LDAP_DN_PEDANTIC ) {
972 if ( !strncmp( p, "OID.", 4 )
973 || !strncmp( p, "oid.", 4 ) ) {
975 state = B4OIDATTRTYPE;
979 if ( !strncasecmp( p, "oid.", 4 ) ) {
981 state = B4OIDATTRTYPE;
987 state = B4STRINGATTRTYPE;
990 case B4OIDATTRTYPE: {
991 int err = LDAP_SUCCESS;
994 type = parse_numericoid( &p, &err, 0 );
995 if ( type == NULL ) {
998 attrType = LDAP_MALLOC( sizeof( struct berval ) );
999 if ( attrType== NULL ) {
1000 rc = LDAP_NO_MEMORY;
1003 attrType->bv_val = type;
1004 attrType->bv_len = strlen( type );
1005 attrTypeEncoding = LDAP_AVA_BINARY;
1007 state = B4AVAEQUALS;
1011 case B4STRINGATTRTYPE: {
1012 const char *startPos, *endPos = NULL;
1016 * the starting char has been found to be
1017 * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
1018 * FIXME: DCE attr types seem to have a more
1019 * restrictive syntax (no '-' ...)
1021 for ( startPos = p++; p[ 0 ]; p++ ) {
1022 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
1026 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
1029 * RFC 2253 does not explicitly
1030 * allow lang extensions to attribute
1033 if ( flags & LDAP_DN_PEDANTIC ) {
1038 * we trim ';' and following lang
1039 * and so from attribute types
1042 for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
1043 || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
1051 len = ( endPos ? endPos : p ) - startPos;
1056 assert( attrType == NULL );
1057 attrType = LDAP_MALLOC( sizeof( struct berval ) );
1058 if ( attrType == NULL ) {
1059 rc = LDAP_NO_MEMORY;
1062 attrType->bv_val = LDAP_STRNDUP( startPos, len );
1063 if ( attrType->bv_val == NULL ) {
1064 rc = LDAP_NO_MEMORY;
1067 attrType->bv_len = len;
1068 attrTypeEncoding = LDAP_AVA_STRING;
1071 * here we need to decide whether to use it as is
1072 * or turn it in OID form; as a consequence, we
1073 * need to decide whether to binary encode the value
1076 state = B4AVAEQUALS;
1081 /* spaces may not be allowed */
1082 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1083 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1088 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1093 /* need equal sign */
1094 if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1099 /* spaces may not be allowed */
1100 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1101 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1106 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1112 * octothorpe means a BER encoded value will follow
1113 * FIXME: I don't think DCE will allow it
1115 if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1117 attrValueEncoding = LDAP_AVA_BINARY;
1118 state = B4BINARYVALUE;
1122 /* STRING value expected */
1125 * if we're pedantic, an attribute type in OID form
1126 * SHOULD imply a BER encoded attribute value; we
1127 * should at least issue a warning
1129 if ( ( flags & LDAP_DN_PEDANTIC )
1130 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1131 /* OID attrType SHOULD use binary encoding */
1135 attrValueEncoding = LDAP_AVA_STRING;
1138 * LDAPv2 allows the attribute value to be quoted;
1139 * also, IA5 values are expected, in principle
1141 if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1142 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1144 state = B4IA5VALUEQUOTED;
1148 if ( LDAP_DN_LDAPV2( flags ) ) {
1155 * here STRING means RFC 2253 string
1156 * FIXME: what about DCE strings?
1158 state = B4STRINGVALUE;
1162 if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
1170 switch ( LDAP_DN_FORMAT( flags ) ) {
1171 case LDAP_DN_FORMAT_LDAP:
1172 case LDAP_DN_FORMAT_LDAPV3:
1173 if ( str2strval( p, &attrValue, &p, flags,
1174 &attrValueEncoding ) ) {
1179 case LDAP_DN_FORMAT_DCE:
1180 if ( DCE2strval( p, &attrValue, &p, flags ) ) {
1193 if ( IA52strval( p, &attrValue, &p, flags ) ) {
1200 case B4IA5VALUEQUOTED:
1202 /* lead quote already stripped */
1203 if ( quotedIA52strval( p, &attrValue,
1217 * we accept empty values
1219 ava = ldapava_new( attrType, attrValue,
1220 attrValueEncoding );
1221 if ( ava == NULL ) {
1222 rc = LDAP_NO_MEMORY;
1226 rdn = ldapava_append_to_rdn( newRDN, ava );
1227 if ( rdn == NULL ) {
1228 rc = LDAP_NO_MEMORY;
1234 * if we got an AVA separator ('+', or ',' for DCE )
1235 * we expect a new AVA for this RDN; otherwise
1236 * we add the RDN to the DN
1238 switch ( LDAP_DN_FORMAT( flags ) ) {
1239 case LDAP_DN_FORMAT_LDAP:
1240 case LDAP_DN_FORMAT_LDAPV3:
1241 case LDAP_DN_FORMAT_LDAPV2:
1242 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1247 case LDAP_DN_FORMAT_DCE:
1248 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1256 * the RDN is over, phew
1263 /* they should have been used in an AVA */
1279 /* They are set to NULL after they're used in an AVA */
1281 ber_bvfree( attrType );
1285 ber_bvfree( attrValue );
1289 ldap_rdnfree( newRDN );
1295 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n",
1303 * reads in a UTF-8 string value, unescaping stuff:
1304 * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1305 * '\' + HEXPAIR(p) -> unhex(p)
1308 str2strval( const char *str, struct berval **val, const char **next, unsigned flags, unsigned *retFlags )
1310 const char *p, *startPos, *endPos = NULL;
1311 ber_len_t len, escapes, unescapes;
1320 for ( startPos = p = str, escapes = 0, unescapes = 0; p[ 0 ]; p++ ) {
1321 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1323 if ( p[ 0 ] == '\0' ) {
1326 if ( ( p == startPos + 1 && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1327 || ( LDAP_DN_VALUE_END( p[ 1 ] ) && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
1328 || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1333 if ( LDAP_DN_HEXPAIR( p ) ) {
1336 hexstr2bin( p, &c );
1339 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1342 * we assume the string is UTF-8
1344 *retFlags = LDAP_AVA_NONPRINTABLE;
1351 if ( LDAP_DN_PEDANTIC & flags ) {
1355 * FIXME: we allow escaping
1356 * of chars that don't need
1357 * to and do not belong to
1358 * HEXDIGITS (we also allow
1359 * single hexdigit; maybe we
1364 } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) )
1365 || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1368 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1370 * FIXME: maybe we can add
1371 * escapes if not pedantic?
1378 * we do allow unescaped spaces at the end
1379 * of the value only in non-pedantic mode
1381 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1382 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1383 if ( flags & LDAP_DN_PEDANTIC ) {
1387 /* strip trailing (unescaped) spaces */
1388 for ( endPos = p - 1;
1389 endPos > startPos + 1 &&
1390 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1391 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1398 * FIXME: test memory?
1400 len = ( endPos ? endPos : p ) - startPos - escapes - unescapes;
1401 *val = LDAP_MALLOC( sizeof( struct berval ) );
1402 ( *val )->bv_len = len;
1404 if ( escapes == 0 && unescapes == 0 ) {
1405 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1410 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1411 for ( s = 0, d = 0; d < len; ) {
1412 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1414 if ( ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( startPos[ s ] ) )
1415 || ( s == len - 1 && LDAP_DN_NEEDESCAPE_TRAIL( startPos[ s ] ) )
1416 || LDAP_DN_NEEDESCAPE( startPos[ s ] ) ) {
1417 ( *val )->bv_val[ d++ ] =
1420 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1423 hexstr2bin( &startPos[ s ], &c );
1424 ( *val )->bv_val[ d++ ] = c;
1429 * we allow escaping of chars
1430 * that do not need to
1432 ( *val )->bv_val[ d++ ] =
1437 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1441 ( *val )->bv_val[ d ] = '\0';
1442 assert( strlen( ( *val )->bv_val ) == len );
1452 DCE2strval( const char *str, struct berval **val, const char **next, unsigned flags )
1454 const char *p, *startPos, *endPos = NULL;
1455 ber_len_t len, escapes;
1464 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1465 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1467 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1474 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1479 * FIXME: can we accept anything else? I guess we need
1480 * to stop if a value is not legal
1485 * (unescaped) trailing spaces are trimmed must be silently ignored;
1488 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1489 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1490 if ( flags & LDAP_DN_PEDANTIC ) {
1494 /* strip trailing (unescaped) spaces */
1495 for ( endPos = p - 1;
1496 endPos > startPos + 1 &&
1497 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1498 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1505 len = ( endPos ? endPos : p ) - startPos - escapes;
1506 *val = LDAP_MALLOC( sizeof( struct berval ) );
1507 ( *val )->bv_len = len;
1508 if ( escapes == 0 ){
1509 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1514 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1515 for ( s = 0, d = 0; d < len; ) {
1517 * This point is reached only if escapes
1518 * are properly used, so all we need to
1521 if ( LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1525 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1527 ( *val )->bv_val[ d ] = '\0';
1528 assert( strlen( ( *val )->bv_val ) == len );
1537 IA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1539 const char *p, *startPos, *endPos = NULL;
1540 ber_len_t len, escapes;
1553 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1554 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1556 if ( p[ 0 ] == '\0' ) {
1560 if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1561 && ( LDAP_DN_PEDANTIC & flags ) ) {
1566 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1571 * FIXME: can we accept anything else? I guess we need
1572 * to stop if a value is not legal
1576 /* strip trailing (unescaped) spaces */
1578 endPos > startPos + 1 &&
1579 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1580 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1585 *val = LDAP_MALLOC( sizeof( struct berval ) );
1586 len = ( endPos ? endPos : p ) - startPos - escapes;
1587 ( *val )->bv_len = len;
1588 if ( escapes == 0 ) {
1589 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1594 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1595 for ( s = 0, d = 0; d < len; ) {
1596 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1599 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1601 ( *val )->bv_val[ d ] = '\0';
1602 assert( strlen( ( *val )->bv_val ) == len );
1610 quotedIA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1612 const char *p, *startPos, *endPos = NULL;
1614 unsigned escapes = 0;
1623 /* initial quote already eaten */
1624 for ( startPos = p = str; p[ 0 ]; p++ ) {
1626 * According to RFC 1779, the quoted value can
1627 * contain escaped as well as unescaped special values;
1628 * as a consequence we tolerate escaped values
1629 * (e.g. '"\,"' -> '\,') and escape unescaped specials
1630 * (e.g. '","' -> '\,').
1632 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1633 if ( p[ 1 ] == '\0' ) {
1638 if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1639 && ( LDAP_DN_PEDANTIC & flags ) ) {
1641 * do we allow to escape normal chars?
1642 * LDAPv2 does not allow any mechanism
1643 * for escaping chars with '\' and hex
1650 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1652 /* eat closing quotes */
1658 * FIXME: can we accept anything else? I guess we need
1659 * to stop if a value is not legal
1663 if ( endPos == NULL ) {
1667 /* Strip trailing (unescaped) spaces */
1668 for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1672 len = endPos - startPos - escapes;
1674 *val = LDAP_MALLOC( sizeof( struct berval ) );
1675 ( *val )->bv_len = len;
1676 if ( escapes == 0 ) {
1677 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1682 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1683 ( *val )->bv_len = len;
1685 for ( s = d = 0; d < len; ) {
1686 if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1689 ( *val )->bv_val[ d++ ] = str[ s++ ];
1691 ( *val )->bv_val[ d ] = '\0';
1692 assert( strlen( ( *val )->bv_val ) == len );
1701 hexstr2bin( const char *str, char *c )
1711 if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1715 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c1 ) ) {
1718 assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) );
1725 if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1729 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c2 ) ) {
1730 *c += c2 - 'A' + 10;
1732 assert( 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 #ifdef PRETTY_ESCAPE
1904 int escaped_ascii_len = LDAP_DN_IS_PRETTY( flags ) ? 2 : 3;
1905 #endif /* PRETTY_ESCAPE */
1911 if ( val->bv_len == 0 ) {
1915 for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
1916 cl = ldap_utf8_charlen( p );
1918 /* illegal utf-8 char! */
1921 } else if ( cl > 1 ) {
1924 for ( cnt = 1; cnt < cl; cnt++ ) {
1925 if ( ( p[ cnt ] & 0x80 ) == 0x00 ) {
1929 l += escaped_byte_len * cl;
1931 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
1932 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1933 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
1934 #ifdef PRETTY_ESCAPE
1935 if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) {
1938 * there might be some chars we want
1939 * to escape in form of a couple
1940 * of hexdigits for optimization purposes
1945 l += escaped_ascii_len;
1947 #else /* ! PRETTY_ESCAPE */
1949 #endif /* ! PRETTY_ESCAPE */
1962 * convert to string representation, escaping with hex the UTF-8 stuff;
1963 * assume the destination has enough room for escaping
1966 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
1968 ber_len_t s, d, end;
1974 if ( val->bv_len == 0 ) {
1980 * we assume the string has enough room for the hex encoding
1983 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
1984 ber_len_t cl = ldap_utf8_charlen( &val->bv_val[ s ] );
1987 * there might be some chars we want to escape in form
1988 * of a couple of hexdigits for optimization purposes
1990 if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) )
1991 #ifdef PRETTY_ESCAPE
1992 || LDAP_DN_WILLESCAPE_HEX( flags, val->bv_val[ s ] )
1993 #else /* ! PRETTY_ESCAPE */
1994 || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
1995 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
1996 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
1998 #endif /* ! PRETTY_ESCAPE */
2002 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2007 } else if ( cl > 1 ) {
2009 str[ d++ ] = val->bv_val[ s++ ];
2013 #ifdef PRETTY_ESCAPE
2014 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2015 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2016 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2018 if ( !LDAP_DN_IS_PRETTY( flags ) ) {
2019 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2025 #endif /* PRETTY_ESCAPE */
2026 str[ d++ ] = val->bv_val[ s++ ];
2036 * Length of the IA5 string representation (no UTF-8 allowed)
2039 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
2048 if ( val->bv_len == 0 ) {
2052 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2054 * Turn value into a binary encoded BER
2059 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2060 if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2061 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2062 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2077 * convert to string representation (np UTF-8)
2078 * assume the destination has enough room for escaping
2081 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2083 ber_len_t s, d, end;
2089 if ( val->bv_len == 0 ) {
2094 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2096 * Turn value into a binary encoded BER
2103 * we assume the string has enough room for the hex encoding
2107 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2108 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2109 || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2110 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2113 str[ d++ ] = val->bv_val[ s++ ];
2123 * Length of the (supposedly) DCE string representation,
2124 * accounting for escaped hex of UTF-8 chars
2127 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2136 if ( val->bv_len == 0 ) {
2140 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2142 * FIXME: Turn the value into a binary encoded BER?
2147 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2148 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2163 * convert to (supposedly) DCE string representation,
2164 * escaping with hex the UTF-8 stuff;
2165 * assume the destination has enough room for escaping
2168 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2176 if ( val->bv_len == 0 ) {
2181 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2183 * FIXME: Turn the value into a binary encoded BER?
2191 * we assume the string has enough room for the hex encoding
2195 for ( s = 0, d = 0; s < val->bv_len; ) {
2196 if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2199 str[ d++ ] = val->bv_val[ s++ ];
2209 * Length of the (supposedly) AD canonical string representation,
2210 * accounting for escaped hex of UTF-8 chars
2213 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2222 if ( val->bv_len == 0 ) {
2226 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2228 * FIXME: Turn the value into a binary encoded BER?
2233 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2234 if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2249 * convert to (supposedly) AD string representation,
2250 * escaping with hex the UTF-8 stuff;
2251 * assume the destination has enough room for escaping
2254 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2262 if ( val->bv_len == 0 ) {
2267 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2269 * FIXME: Turn the value into a binary encoded BER?
2277 * we assume the string has enough room for the hex encoding
2281 for ( s = 0, d = 0; s < val->bv_len; ) {
2282 if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2285 str[ d++ ] = val->bv_val[ s++ ];
2295 * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2296 * the first part of the AD representation of the DN is written in DNS
2297 * form, i.e. dot separated domain name components (as suggested
2298 * by Luke Howard, http://www.padl.com/~lukeh)
2301 dn2domain( LDAPDN *dn, char *str, int *iRDN )
2304 int domain = 0, first = 1;
2305 ber_len_t l = 1; /* we move the null also */
2307 /* we are guaranteed there's enough memory in str */
2313 assert( *iRDN >= 0 );
2315 for ( i = *iRDN; i >= 0; i-- ) {
2319 assert( dn[ i ][ 0 ] );
2322 assert( rdn[ 0 ][ 0 ] );
2323 ava = rdn[ 0 ][ 0 ];
2325 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2333 AC_MEMCPY( str, ava->la_value->bv_val,
2334 ava->la_value->bv_len + 1);
2335 l += ava->la_value->bv_len;
2338 AC_MEMCPY( str + ava->la_value->bv_len + 1, str, l);
2339 AC_MEMCPY( str, ava->la_value->bv_val,
2340 ava->la_value->bv_len );
2341 str[ ava->la_value->bv_len ] = '.';
2342 l += ava->la_value->bv_len + 1;
2352 rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
2353 int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2360 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2361 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2363 /* len(type) + '=' + '+' | ',' */
2364 l += ava->la_attr->bv_len + 2;
2366 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2367 /* octothorpe + twice the length */
2368 l += 1 + 2 * ava->la_value->bv_len;
2372 unsigned f = flags | ava->la_flags;
2374 if ( ( *s2l )( ava->la_value, f, &vl ) ) {
2387 rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
2388 int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2393 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2394 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2396 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2397 ava->la_attr->bv_len );
2398 l += ava->la_attr->bv_len;
2402 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2404 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2407 l += 2 * ava->la_value->bv_len;
2411 unsigned f = flags | ava->la_flags;
2413 if ( ( *s2s )( ava->la_value, &str[ l ], f, &vl ) ) {
2418 str[ l++ ] = ( rdn[ iAVA + 1 ] ? '+' : ',' );
2427 rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2434 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2435 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2437 /* len(type) + '=' + ',' | '/' */
2438 l += ava->la_attr->bv_len + 2;
2440 switch ( ava->la_flags ) {
2441 case LDAP_AVA_BINARY:
2442 /* octothorpe + twice the length */
2443 l += 1 + 2 * ava->la_value->bv_len;
2446 case LDAP_AVA_STRING: {
2448 unsigned f = flags | ava->la_flags;
2450 if ( strval2DCEstrlen( ava->la_value, f, &vl ) ) {
2468 rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2473 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2474 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2479 str[ l++ ] = ( iAVA ? ',' : '/' );
2482 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2483 ava->la_attr->bv_len );
2484 l += ava->la_attr->bv_len;
2488 switch ( ava->la_flags ) {
2489 case LDAP_AVA_BINARY:
2491 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2494 l += 2 * ava->la_value->bv_len;
2497 case LDAP_AVA_STRING: {
2499 unsigned f = flags | ava->la_flags;
2501 if ( strval2DCEstr( ava->la_value, &str[ l ], f, &vl ) ) {
2519 rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2529 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2530 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2533 l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
2535 /* FIXME: are binary values allowed in UFN? */
2536 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2537 /* octothorpe + twice the value */
2538 l += 1 + 2 * ava->la_value->bv_len;
2542 unsigned f = flags | ava->la_flags;
2544 if ( strval2strlen( ava->la_value, f, &vl ) ) {
2557 rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
2562 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2563 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2565 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2567 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2570 l += 2 * ava->la_value->bv_len;
2574 unsigned f = flags | ava->la_flags;
2576 if ( strval2str( ava->la_value, &str[ l ], f, &vl ) ) {
2582 if ( rdn[ iAVA + 1 ]) {
2583 AC_MEMCPY( &str[ l ], " + ", 3 );
2587 AC_MEMCPY( &str[ l ], ", ", 2 );
2598 rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2608 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2609 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2614 /* FIXME: are binary values allowed in UFN? */
2615 switch ( ava->la_flags ) {
2616 case LDAP_AVA_BINARY:
2617 /* octothorpe + twice the value */
2618 l += 1 + 2 * ava->la_value->bv_len;
2621 case LDAP_AVA_STRING: {
2623 unsigned f = flags | ava->la_flags;
2625 if ( strval2ADstrlen( ava->la_value, f, &vl ) ) {
2643 rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2648 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2649 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2654 str[ l++ ] = ( iAVA ? ',' : '/' );
2657 switch ( ava->la_flags ) {
2658 case LDAP_AVA_BINARY:
2660 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2663 l += 2 * ava->la_value->bv_len;
2666 case LDAP_AVA_STRING: {
2668 unsigned f = flags | ava->la_flags;
2670 if ( strval2ADstr( ava->la_value, &str[ l ], f, &vl ) ) {
2690 * Returns in str a string representation of rdn based on flags.
2691 * There is some duplication of code between this and ldap_dn2str;
2692 * this is wanted to reduce the allocation of temporary buffers.
2695 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2702 if ( rdn == NULL ) {
2703 *str = LDAP_STRDUP( "" );
2704 return( LDAP_SUCCESS );
2708 * This routine wastes "back" bytes at the end of the string
2712 switch ( LDAP_DN_FORMAT( flags ) ) {
2713 case LDAP_DN_FORMAT_LDAPV3:
2714 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2715 return( LDAP_OTHER );
2719 case LDAP_DN_FORMAT_LDAPV2:
2720 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2721 return( LDAP_OTHER );
2725 case LDAP_DN_FORMAT_UFN:
2726 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2727 return( LDAP_OTHER );
2731 case LDAP_DN_FORMAT_DCE:
2732 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2733 return( LDAP_OTHER );
2737 case LDAP_DN_FORMAT_AD_CANONICAL:
2738 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2739 return( LDAP_OTHER );
2744 return( LDAP_INVALID_DN_SYNTAX );
2747 *str = LDAP_MALLOC( l + 1 );
2749 switch ( LDAP_DN_FORMAT( flags ) ) {
2750 case LDAP_DN_FORMAT_LDAPV3:
2751 rc = rdn2str( rdn, *str, flags, &l, strval2str );
2755 case LDAP_DN_FORMAT_LDAPV2:
2756 rc = rdn2str( rdn, *str, flags, &l, strval2IA5str );
2760 case LDAP_DN_FORMAT_UFN:
2761 rc = rdn2UFNstr( rdn, *str, flags, &l );
2765 case LDAP_DN_FORMAT_DCE:
2766 rc = rdn2DCEstr( rdn, *str, flags, &l, 1 );
2770 case LDAP_DN_FORMAT_AD_CANONICAL:
2771 rc = rdn2ADstr( rdn, *str, flags, &l, 1 );
2776 /* need at least one of the previous */
2777 return( LDAP_OTHER );
2781 ldap_memfree( *str );
2782 return( LDAP_OTHER );
2785 ( *str )[ l - back ] = '\0';
2787 return( LDAP_SUCCESS );
2791 * Very bulk implementation; many optimizations can be performed
2792 * - a NULL dn results in an empty string ""
2795 * a) what do we do if a UTF-8 string must be converted in LDAPv2?
2796 * we must encode it in binary form ('#' + HEXPAIRs)
2797 * b) does DCE/AD support UTF-8?
2798 * no clue; don't think so.
2799 * c) what do we do when binary values must be converted in UTF/DCE/AD?
2800 * use binary encoded BER
2802 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
2805 int rc = LDAP_OTHER;
2808 /* stringifying helpers for LDAPv3/LDAPv2 */
2809 int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2810 int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2814 Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2str(%u)\n%s%s", flags, "", "" );
2819 * a null dn means an empty dn string
2820 * FIXME: better raise an error?
2823 *str = LDAP_STRDUP( "" );
2824 return( LDAP_SUCCESS );
2827 switch ( LDAP_DN_FORMAT( flags ) ) {
2828 case LDAP_DN_FORMAT_LDAPV3:
2829 sv2l = strval2strlen;
2833 case LDAP_DN_FORMAT_LDAPV2:
2834 sv2l = strval2IA5strlen;
2835 sv2s = strval2IA5str;
2838 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2840 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2842 if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
2843 goto return_results;
2849 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2850 rc = LDAP_NO_MEMORY;
2854 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
2856 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2858 if ( rdn2str( rdn, &( *str )[ l ], flags,
2862 goto return_results;
2870 * trim the last ',' (the allocated memory
2871 * is one byte longer than required)
2873 ( *str )[ len - 1 ] = '\0';
2878 case LDAP_DN_FORMAT_UFN: {
2881 * FIXME: quoting from RFC 1781:
2883 To take a distinguished name, and generate a name of this format with
2884 attribute types omitted, the following steps are followed.
2886 1. If the first attribute is of type CommonName, the type may be
2889 2. If the last attribute is of type Country, the type may be
2892 3. If the last attribute is of type Country, the last
2893 Organisation attribute may have the type omitted.
2895 4. All attributes of type OrganisationalUnit may have the type
2896 omitted, unless they are after an Organisation attribute or
2897 the first attribute is of type OrganisationalUnit.
2899 * this should be the pedantic implementation.
2901 * Here the standard implementation reflects
2902 * the one historically provided by OpenLDAP
2903 * (and UMIch, I presume), with the variant
2904 * of spaces and plusses (' + ') separating
2907 * A non-standard but nice implementation could
2908 * be to turn the final "dc" attributes into a
2909 * dot-separated domain.
2911 * Other improvements could involve the use of
2912 * friendly country names and so.
2915 int leftmost_dc = -1;
2917 #endif /* DC_IN_UFN */
2919 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2921 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2923 if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
2924 goto return_results;
2929 if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
2930 if ( leftmost_dc == -1 ) {
2936 #endif /* DC_IN_UFN */
2939 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2940 rc = LDAP_NO_MEMORY;
2945 if ( leftmost_dc == -1 ) {
2946 #endif /* DC_IN_UFN */
2947 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
2949 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2951 if ( rdn2UFNstr( rdn, &( *str )[ l ],
2955 goto return_results;
2961 * trim the last ', ' (the allocated memory
2962 * is two bytes longer than required)
2964 ( *str )[ len - 2 ] = '\0';
2967 last_iRDN = iRDN - 1;
2969 for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
2971 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2973 if ( rdn2UFNstr( rdn, &( *str )[ l ],
2977 goto return_results;
2982 if ( !dn2domain( dn, &( *str )[ l ], &last_iRDN ) ) {
2985 goto return_results;
2988 /* the string is correctly terminated by dn2domain */
2990 #endif /* DC_IN_UFN */
2996 case LDAP_DN_FORMAT_DCE:
2998 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3000 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3002 if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
3003 goto return_results;
3009 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3010 rc = LDAP_NO_MEMORY;
3014 for ( l = 0; iRDN--; ) {
3016 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3018 if ( rdn2DCEstr( rdn, &( *str )[ l ], flags,
3022 goto return_results;
3029 ( *str )[ len ] = '\0';
3034 case LDAP_DN_FORMAT_AD_CANONICAL: {
3037 * Sort of UFN for DCE DNs: a slash ('/') separated
3038 * global->local DN with no types; strictly speaking,
3039 * the naming context should be a domain, which is
3040 * written in DNS-style, e.g. dot-deparated.
3044 * "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3048 * "microsoft.com/People/Bill,Gates"
3050 for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
3052 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3054 if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
3055 goto return_results;
3061 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3062 rc = LDAP_NO_MEMORY;
3067 if ( iRDN && dn2domain( dn, *str, &iRDN ) ) {
3068 for ( l = strlen( *str ); iRDN >= 0 ; iRDN-- ) {
3070 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3072 if ( rdn2ADstr( rdn, &( *str )[ l ],
3073 flags, &rdnl, 0 ) ) {
3076 goto return_results;
3085 * Strictly speaking, AD canonical requires
3086 * a DN to be in the form "..., dc=smtg",
3087 * i.e. terminated by a domain component
3089 if ( flags & LDAP_DN_PEDANTIC ) {
3092 rc = LDAP_INVALID_DN_SYNTAX;
3096 for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3098 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3100 if ( rdn2ADstr( rdn, &( *str )[ l ],
3101 flags, &rdnl, first ) ) {
3104 goto return_results;
3113 ( *str )[ len ] = '\0';
3120 return( LDAP_INVALID_DN_SYNTAX );
3124 Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2str(%s,%u)=%d\n", *str, flags, rc );