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>
20 #include <ac/socket.h>
21 #include <ac/string.h>
26 /* extension to UFN that turns trailing "dc=value" rdns in DNS style,
27 * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */
30 static int dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout );
32 /* from libraries/libldap/schema.c */
33 extern char * parse_numericoid(const char **sp, int *code, const int flags);
35 /* parsing/printing routines */
36 static int str2strval( const char *str, struct berval **val,
37 const char **next, unsigned flags, unsigned *retFlags );
38 static int DCE2strval( const char *str, struct berval **val,
39 const char **next, unsigned flags );
40 static int IA52strval( const char *str, struct berval **val,
41 const char **next, unsigned flags );
42 static int quotedIA52strval( const char *str, struct berval **val,
43 const char **next, unsigned flags );
44 static int hexstr2binval( const char *str, struct berval **val,
45 const char **next, unsigned flags );
46 static int hexstr2bin( const char *str, char *c );
47 static int byte2hexpair( const char *val, char *pair );
48 static int binval2hexstr( struct berval *val, char *str );
49 static int strval2strlen( struct berval *val, unsigned flags,
51 static int strval2str( struct berval *val, char *str, unsigned flags,
53 static int strval2IA5strlen( struct berval *val, unsigned flags,
55 static int strval2IA5str( struct berval *val, char *str, unsigned flags,
57 static int strval2DCEstrlen( struct berval *val, unsigned flags,
59 static int strval2DCEstr( struct berval *val, char *str, unsigned flags,
61 static int strval2ADstrlen( struct berval *val, unsigned flags,
63 static int strval2ADstr( struct berval *val, char *str, unsigned flags,
65 static int dn2domain( LDAPDN *dn, char *str, int *iRDN );
68 static LDAPAVA * ldapava_new(
69 const struct berval *attr, const struct berval *val, unsigned flags );
70 static LDAPRDN * ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava );
71 static LDAPRDN * ldapava_insert_into_rdn(
72 LDAPRDN *rdn, LDAPAVA *ava, unsigned where );
73 static LDAPDN * ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn );
74 static LDAPDN * ldapava_insert_into_dn(
75 LDAPDN *dn, LDAPRDN *rdn, unsigned where );
77 /* Higher level helpers */
78 static int rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
79 int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
80 static int rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
81 int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
82 static int rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
83 static int rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len );
84 static int rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
85 static int rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flag, ber_len_t *len, int first );
86 static int rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
87 static int rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first );
90 * RFC 1823 ldap_get_dn
93 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
98 Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
100 if ( entry == NULL ) {
101 ld->ld_errno = LDAP_PARAM_ERROR;
105 tmp = *entry->lm_ber; /* struct copy */
106 if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
107 ld->ld_errno = LDAP_DECODING_ERROR;
115 * RFC 1823 ldap_dn2ufn
118 ldap_dn2ufn( LDAP_CONST char *dn )
122 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
124 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_UFN );
130 * RFC 1823 ldap_explode_dn
133 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
136 char **values = NULL;
138 unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
140 Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
142 if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP )
147 if( tmpDN == NULL ) {
148 values = LDAP_MALLOC( sizeof( char * ) );
149 if( values == NULL ) return NULL;
155 for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) {
156 char *str, **v = NULL;
158 ldap_rdn2str( tmpDN[ iRDN ][ 0 ], &str, flag );
160 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iRDN ) );
162 LBER_VFREE( values );
163 ldap_dnfree( tmpDN );
167 values[ iRDN ] = str;
170 values[ iRDN ] = NULL;
175 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
178 char **values = NULL;
182 notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
184 Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
187 * we only parse the first rdn
188 * FIXME: we prefer efficiency over checking if the _ENTIRE_
191 if ( ldap_str2rdn( rdn, &tmpRDN, &p, LDAP_DN_FORMAT_LDAP )
196 for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) {
197 ber_len_t l = 0, vl, al = 0;
198 char *str, **v = NULL;
199 LDAPAVA *ava = tmpRDN[ iAVA ][ 0 ];
201 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iAVA ) );
207 if ( ava->la_flags == LDAP_AVA_BINARY ) {
208 vl = 1 + 2 * ava->la_value->bv_len;
211 if ( strval2strlen( ava->la_value,
212 ava->la_flags, &vl ) ) {
218 al = ava->la_attr->bv_len;
219 l = vl + ava->la_attr->bv_len + 1;
221 str = LDAP_MALLOC( l + 1 );
222 AC_MEMCPY( str, ava->la_attr->bv_val,
223 ava->la_attr->bv_len );
228 str = LDAP_MALLOC( l + 1 );
231 if ( ava->la_flags == LDAP_AVA_BINARY ) {
233 if ( binval2hexstr( ava->la_value, &str[ al ] ) ) {
238 if ( strval2str( ava->la_value, &str[ al ],
239 ava->la_flags, &vl ) ) {
245 values[ iAVA ] = str;
247 values[ iAVA ] = NULL;
249 ldap_rdnfree( tmpRDN );
254 LBER_VFREE( values );
255 ldap_rdnfree( tmpRDN );
260 ldap_dn2dcedn( LDAP_CONST char *dn )
264 Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
266 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_DCE );
272 ldap_dcedn2dn( LDAP_CONST char *dce )
276 Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
278 ( void )dn2dn( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
284 ldap_dn2ad_canonical( LDAP_CONST char *dn )
288 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
290 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP,
291 &out, LDAP_DN_FORMAT_AD_CANONICAL );
297 ldap_dn_normalize( const char *in, unsigned iflags, char **out, unsigned oflags )
301 Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );
303 return dn2dn( in, iflags, out, oflags);
307 * helper that changes the string representation of dnin
308 * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
311 * LDAP_DN_FORMAT_LDAP (rfc 2253 and ldapbis liberal,
312 * plus some rfc 1779)
313 * LDAP_DN_FORMAT_LDAPV3 (rfc 2253 and ldapbis)
314 * LDAP_DN_FORMAT_LDAPV2 (rfc 1779)
315 * LDAP_DN_FORMAT_DCE (?)
317 * fout can be any of the above except
318 * LDAP_DN_FORMAT_LDAP
320 * LDAP_DN_FORMAT_UFN (rfc 1781, partial and with extensions)
321 * LDAP_DN_FORMAT_AD_CANONICAL (?)
324 dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout )
327 LDAPDN *tmpDN = NULL;
333 if ( dnin == NULL ) {
334 return( LDAP_SUCCESS );
337 rc = ldap_str2dn( dnin , &tmpDN, fin );
338 if ( rc != LDAP_SUCCESS ) {
342 rc = ldap_dn2str( tmpDN, dnout, fout );
344 ldap_dnfree( tmpDN );
352 /* #define B4ATTRTYPE 0x0001 */
353 #define B4OIDATTRTYPE 0x0002
354 #define B4STRINGATTRTYPE 0x0003
356 #define B4AVAEQUALS 0x0100
357 #define B4AVASEP 0x0200
358 #define B4RDNSEP 0x0300
359 #define GOTAVA 0x0400
361 #define B4ATTRVALUE 0x0010
362 #define B4STRINGVALUE 0x0020
363 #define B4IA5VALUEQUOTED 0x0030
364 #define B4IA5VALUE 0x0040
365 #define B4BINARYVALUE 0x0050
367 /* Helpers (mostly from slapd.h; maybe it should be rewritten from this) */
368 #define LDAP_DN_ASCII_SPACE(c) \
369 ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
370 #define LDAP_DN_ASCII_LOWER(c) ( (c) >= 'a' && (c) <= 'z' )
371 #define LDAP_DN_ASCII_UPPER(c) ( (c) >= 'A' && (c) <= 'Z' )
372 #define LDAP_DN_ASCII_ALPHA(c) \
373 ( LDAP_DN_ASCII_LOWER(c) || LDAP_DN_ASCII_UPPER(c) )
374 #define LDAP_DN_ASCII_DIGIT(c) ( (c) >= '0' && (c) <= '9' )
375 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) ( (c) >= 'a' && (c) <= 'f' )
376 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) ( (c) >= 'A' && (c) <= 'F' )
377 #define LDAP_DN_ASCII_HEXDIGIT(c) \
378 ( LDAP_DN_ASCII_DIGIT(c) \
379 || LDAP_DN_ASCII_LCASE_HEXALPHA(c) \
380 || LDAP_DN_ASCII_UCASE_HEXALPHA(c) )
381 #define LDAP_DN_ASCII_ALNUM(c) \
382 ( LDAP_DN_ASCII_ALPHA(c) || LDAP_DN_ASCII_DIGIT(c) )
383 #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' )
386 #define LDAP_DN_OID_LEADCHAR(c) ( LDAP_DN_ASCII_DIGIT(c) )
387 #define LDAP_DN_DESC_LEADCHAR(c) ( LDAP_DN_ASCII_ALPHA(c) )
388 #define LDAP_DN_DESC_CHAR(c) ( LDAP_DN_ASCII_ALNUM(c) || (c) == '-' )
389 #define LDAP_DN_LANG_SEP(c) ( (c) == ';' )
390 #define LDAP_DN_ATTRDESC_CHAR(c) \
391 ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
393 /* special symbols */
394 #define LDAP_DN_AVA_EQUALS(c) ( (c) == '=' )
395 #define LDAP_DN_AVA_SEP(c) ( (c) == '+' )
396 #define LDAP_DN_RDN_SEP(c) ( (c) == ',' )
397 #define LDAP_DN_RDN_SEP_V2(c) ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
398 #define LDAP_DN_OCTOTHORPE(c) ( (c) == '#' )
399 #define LDAP_DN_QUOTES(c) ( (c) == '\"' )
400 #define LDAP_DN_ESCAPE(c) ( (c) == '\\' )
401 #define LDAP_DN_VALUE_END(c) \
402 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
403 #define LDAP_DN_NE(c) \
404 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
405 || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
406 #define LDAP_DN_NEEDESCAPE(c) \
407 ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
408 #define LDAP_DN_NEEDESCAPE_LEAD(c) \
409 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) )
410 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
411 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
412 #define LDAP_DN_WILLESCAPE_CHAR( c) \
413 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
414 #define LDAP_DN_IS_PRETTY( f ) ( (f) & LDAP_DN_PRETTY )
415 #define LDAP_DN_WILLESCAPE(f, c) \
416 ( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
419 #define LDAP_DN_VALUE_END_V2(c) \
420 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
422 #define LDAP_DN_V2_SPECIAL(c) \
423 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
424 || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
425 || LDAP_DN_OCTOTHORPE(c) )
426 #define LDAP_DN_V2_PAIR(c) \
427 ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
430 * DCE (mostly from Luke Howard and IBM implementation for AIX)
432 * From: "Application Development Guide - Directory Services" (FIXME: add link?)
433 * Here escapes and valid chars for GDS are considered; as soon as more
434 * specific info is found, the macros will be updated.
436 * Chars: 'a'-'z', 'A'-'Z', '0'-'9',
437 * '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
439 * Metachars: '/', ',', '=', '\'.
441 * the '\' is used to escape other metachars.
447 * Attribute types must start with alphabetic chars and can contain
448 * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
450 #define LDAP_DN_RDN_SEP_DCE(c) ( (c) == '/' )
451 #define LDAP_DN_AVA_SEP_DCE(c) ( (c) == ',' )
452 #define LDAP_DN_ESCAPE_DCE(c) ( LDAP_DN_ESCAPE(c) )
453 #define LDAP_DN_VALUE_END_DCE(c) \
454 ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
455 #define LDAP_DN_NEEDESCAPE_DCE(c) \
456 ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
459 #define LDAP_DN_RDN_SEP_AD(c) ( (c) == '/' )
460 #define LDAP_DN_ESCAPE_AD(c) ( LDAP_DN_ESCAPE(c) )
461 #define LDAP_DN_AVA_SEP_AD(c) ( (c) == ',' ) /* assume same as DCE */
462 #define LDAP_DN_VALUE_END_AD(c) \
463 ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
464 #define LDAP_DN_NEEDESCAPE_AD(c) \
465 ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
468 #define LDAP_DN_HEXPAIR(s) \
469 ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
470 #define LDAP_DC_ATTR "dc"
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 #define LDAP_DN_IS_RDN_DC( rdn ) \
478 ( ( rdn ) && ( rdn )[ 0 ][ 0 ] && !( rdn )[ 1 ] \
479 && ( ( rdn )[ 0 ][ 0 ]->la_flags == LDAP_AVA_STRING ) \
480 && ! strcasecmp( ( rdn )[ 0 ][ 0 ]->la_attr->bv_val, LDAP_DC_ATTR ) )
482 /* Composite rules */
483 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
484 ( LDAP_DN_LDAPV2(f) \
485 || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
486 #define LDAP_DN_ALLOW_SPACES(f) \
487 ( LDAP_DN_LDAPV2(f) \
488 || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
489 #define LDAP_DN_LDAP(f) \
490 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
491 #define LDAP_DN_LDAPV3(f) \
492 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
493 #define LDAP_DN_LDAPV2(f) \
494 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
495 #define LDAP_DN_DCE(f) \
496 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
497 #define LDAP_DN_UFN(f) \
498 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
499 #define LDAP_DN_ADC(f) \
500 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
501 #define LDAP_DN_FORMAT(f) ( (f) & LDAP_DN_FORMAT_MASK )
504 * LDAPAVA helpers (will become part of the API for operations
505 * on structural representations of DNs).
508 ldapava_new( const struct berval *attr, const struct berval *val,
516 ava = LDAP_MALLOC( sizeof( LDAPAVA ) );
518 /* should we test it? */
523 ava->la_attr = ( struct berval * )attr;
524 ava->la_value = ( struct berval * )val;
525 ava->la_flags = flags;
527 ava->la_private = NULL;
533 ldap_avafree( LDAPAVA *ava )
538 /* ava's private must be freed by caller
539 * (at present let's skip this check because la_private
540 * basically holds static data) */
541 assert( ava->la_private == NULL );
544 ber_bvfree( ava->la_attr );
545 ber_bvfree( ava->la_value );
551 ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava )
559 for ( i = 0U; rdn[ i ]; i++ ) {
563 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
564 newRDN[ i ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
565 newRDN[ i ][ 0 ] = ava;
566 newRDN[ i + 1 ] = NULL;
572 ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where )
580 for ( i = 0U; rdn[ i ]; i++ ) {
586 /* assume "at end", which corresponds to
587 * ldapava_append_to_rdn */
590 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
592 /* data after insert point */
593 AC_MEMCPY( &newRDN[ where + 1 ], &newRDN[ where ],
594 ( i - where ) * sizeof( LDAPRDN * ) );
596 newRDN[ where ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
597 newRDN[ where ][ 0 ] = ava;
598 newRDN[ i + 1 ] = NULL;
604 ldap_rdnfree( LDAPRDN *rdn )
612 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
613 assert( rdn[ iAVA ][ 0 ] );
615 ldap_avafree( rdn[ iAVA ][ 0 ] );
622 ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn )
630 for ( i = 0U; dn[ i ]; i++ ) {
634 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
635 newDN[ i ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
636 newDN[ i ][ 0 ] = rdn;
637 newDN[ i + 1 ] = NULL;
643 ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where )
651 for ( i = 0U; dn[ i ]; i++ ) {
657 /* assume "at end", which corresponds to
658 * ldapava_append_to_dn */
661 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
663 /* data after insert point */
664 AC_MEMCPY( &newDN[ where + 1 ], &newDN[ where ],
665 ( i - where ) * sizeof( LDAPDN * ) );
667 newDN[ where ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
668 newDN[ where ][ 0 ] = rdn;
669 newDN[ i + 1 ] = NULL;
675 ldap_dnfree( LDAPDN *dn )
683 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
684 assert( dn[ iRDN ][ 0 ] );
686 ldap_rdnfree( dn[ iRDN ][ 0 ] );
693 * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
694 * into a structural representation of the DN, by separating attribute
695 * types and values encoded in the more appropriate form, which is
696 * string or OID for attribute types and binary form of the BER encoded
697 * value or Unicode string. Formats different from LDAPv3 are parsed
698 * according to their own rules and turned into the more appropriate
699 * form according to LDAPv3.
701 * NOTE: I realize the code is getting spaghettish; it is rather
702 * experimental and will hopefully turn into something more simple
703 * and readable as soon as it works as expected.
707 ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
710 int rc = LDAP_INVALID_DN_SYNTAX;
712 LDAPDN *newDN = NULL;
713 LDAPRDN *newRDN = NULL;
718 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );
722 switch ( LDAP_DN_FORMAT( flags ) ) {
723 case LDAP_DN_FORMAT_LDAP:
724 case LDAP_DN_FORMAT_LDAPV3:
725 case LDAP_DN_FORMAT_LDAPV2:
726 case LDAP_DN_FORMAT_DCE:
729 /* unsupported in str2dn */
730 case LDAP_DN_FORMAT_UFN:
731 case LDAP_DN_FORMAT_AD_CANONICAL:
732 return( LDAP_INVALID_DN_SYNTAX );
735 return( LDAP_OTHER );
738 if ( str[ 0 ] == '\0' ) {
739 return( LDAP_SUCCESS );
743 if ( LDAP_DN_DCE( flags ) ) {
746 * (from Luke Howard: thnx) A RDN separator is required
747 * at the beginning of an (absolute) DN.
749 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
754 } else if ( LDAP_DN_LDAP( flags ) ) {
756 * if dn starts with '/' let's make it a DCE dn
758 if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
759 flags |= LDAP_DN_FORMAT_DCE;
764 for ( ; p[ 0 ]; p++ ) {
768 err = ldap_str2rdn( p, &newRDN, &p, flags );
769 if ( err != LDAP_SUCCESS ) {
774 * We expect a rdn separator
777 switch ( LDAP_DN_FORMAT( flags ) ) {
778 case LDAP_DN_FORMAT_LDAPV3:
779 if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
785 case LDAP_DN_FORMAT_LDAP:
786 case LDAP_DN_FORMAT_LDAPV2:
787 if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
793 case LDAP_DN_FORMAT_DCE:
794 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
803 if ( LDAP_DN_DCE( flags ) ) {
804 /* add in reversed order */
805 dn = ldapava_insert_into_dn( newDN, newRDN, 0 );
807 dn = ldapava_append_to_dn( newDN, newRDN );
818 if ( p[ 0 ] == '\0' ) {
821 * the DN is over, phew
830 ldap_rdnfree( newRDN );
834 ldap_dnfree( newDN );
840 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
849 * Parses a relative DN according to flags up to a rdn separator
850 * or to the end of str.
851 * Returns the rdn and a pointer to the string continuation, which
852 * corresponds to the rdn separator or to '\0' in case the string is over.
855 ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
859 int rc = LDAP_INVALID_DN_SYNTAX;
860 int attrTypeEncoding = LDAP_AVA_STRING,
861 attrValueEncoding = LDAP_AVA_STRING;
863 struct berval *attrType = NULL;
864 struct berval *attrValue = NULL;
866 LDAPRDN *newRDN = NULL;
872 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );
877 switch ( LDAP_DN_FORMAT( flags ) ) {
878 case LDAP_DN_FORMAT_LDAP:
879 case LDAP_DN_FORMAT_LDAPV3:
880 case LDAP_DN_FORMAT_LDAPV2:
881 case LDAP_DN_FORMAT_DCE:
884 /* unsupported in str2dn */
885 case LDAP_DN_FORMAT_UFN:
886 case LDAP_DN_FORMAT_AD_CANONICAL:
887 return( LDAP_INVALID_DN_SYNTAX );
890 return( LDAP_OTHER );
893 if ( str[ 0 ] == '\0' ) {
894 return( LDAP_SUCCESS );
898 for ( ; p[ 0 ] || state == GOTAVA; ) {
901 * The parser in principle advances one token a time,
902 * or toggles state if preferable.
907 * an AttributeType can be encoded as:
908 * - its string representation; in detail, implementations
909 * MUST recognize AttributeType string type names listed
910 * in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
911 * MAY recognize other names.
912 * - its numeric OID (a dotted decimal string); in detail
913 * RFC 2253 asserts that ``Implementations MUST allow
914 * an oid in the attribute type to be prefixed by one
915 * of the character strings "oid." or "OID."''. As soon
916 * as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253
917 * I'm not sure whether this is required or not any
918 * longer; to be liberal, we still implement it.
921 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
922 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
929 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
930 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
935 /* whitespace is allowed (and trimmed) */
937 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
942 /* error: we expected an AVA */
948 if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
949 state = B4OIDATTRTYPE;
953 /* else must be alpha */
954 if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
958 /* LDAPv2 "oid." prefix */
959 if ( LDAP_DN_LDAPV2( flags ) ) {
961 * to be overly pedantic, we only accept
964 if ( flags & LDAP_DN_PEDANTIC ) {
965 if ( !strncmp( p, "OID.", 4 )
966 || !strncmp( p, "oid.", 4 ) ) {
968 state = B4OIDATTRTYPE;
972 if ( !strncasecmp( p, "oid.", 4 ) ) {
974 state = B4OIDATTRTYPE;
980 state = B4STRINGATTRTYPE;
983 case B4OIDATTRTYPE: {
984 int err = LDAP_SUCCESS;
987 type = parse_numericoid( &p, &err, 0 );
988 if ( type == NULL ) {
991 attrType = LDAP_MALLOC( sizeof( struct berval ) );
992 if ( attrType== NULL ) {
996 attrType->bv_val = type;
997 attrType->bv_len = strlen( type );
998 attrTypeEncoding = LDAP_AVA_BINARY;
1000 state = B4AVAEQUALS;
1004 case B4STRINGATTRTYPE: {
1005 const char *startPos, *endPos = NULL;
1009 * the starting char has been found to be
1010 * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
1011 * FIXME: DCE attr types seem to have a more
1012 * restrictive syntax (no '-' ...)
1014 for ( startPos = p++; p[ 0 ]; p++ ) {
1015 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
1019 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
1022 * RFC 2253 does not explicitly
1023 * allow lang extensions to attribute
1026 if ( flags & LDAP_DN_PEDANTIC ) {
1031 * we trim ';' and following lang
1032 * and so from attribute types
1035 for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
1036 || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
1044 len = ( endPos ? endPos : p ) - startPos;
1049 assert( attrType == NULL );
1050 attrType = LDAP_MALLOC( sizeof( struct berval ) );
1051 if ( attrType == NULL ) {
1052 rc = LDAP_NO_MEMORY;
1055 attrType->bv_val = LDAP_STRNDUP( startPos, len );
1056 if ( attrType->bv_val == NULL ) {
1057 rc = LDAP_NO_MEMORY;
1060 attrType->bv_len = len;
1061 attrTypeEncoding = LDAP_AVA_STRING;
1064 * here we need to decide whether to use it as is
1065 * or turn it in OID form; as a consequence, we
1066 * need to decide whether to binary encode the value
1069 state = B4AVAEQUALS;
1074 /* spaces may not be allowed */
1075 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1076 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1081 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1086 /* need equal sign */
1087 if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1092 /* spaces may not be allowed */
1093 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1094 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1099 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1105 * octothorpe means a BER encoded value will follow
1106 * FIXME: I don't think DCE will allow it
1108 if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1110 attrValueEncoding = LDAP_AVA_BINARY;
1111 state = B4BINARYVALUE;
1115 /* STRING value expected */
1118 * if we're pedantic, an attribute type in OID form
1119 * SHOULD imply a BER encoded attribute value; we
1120 * should at least issue a warning
1122 if ( ( flags & LDAP_DN_PEDANTIC )
1123 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1124 /* OID attrType SHOULD use binary encoding */
1128 attrValueEncoding = LDAP_AVA_STRING;
1131 * LDAPv2 allows the attribute value to be quoted;
1132 * also, IA5 values are expected, in principle
1134 if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1135 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1137 state = B4IA5VALUEQUOTED;
1141 if ( LDAP_DN_LDAPV2( flags ) ) {
1148 * here STRING means RFC 2253 string
1149 * FIXME: what about DCE strings?
1151 state = B4STRINGVALUE;
1155 if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
1163 switch ( LDAP_DN_FORMAT( flags ) ) {
1164 case LDAP_DN_FORMAT_LDAP:
1165 case LDAP_DN_FORMAT_LDAPV3:
1166 if ( str2strval( p, &attrValue, &p, flags,
1167 &attrValueEncoding ) ) {
1172 case LDAP_DN_FORMAT_DCE:
1173 if ( DCE2strval( p, &attrValue, &p, flags ) ) {
1186 if ( IA52strval( p, &attrValue, &p, flags ) ) {
1193 case B4IA5VALUEQUOTED:
1195 /* lead quote already stripped */
1196 if ( quotedIA52strval( p, &attrValue,
1210 * we accept empty values
1212 ava = ldapava_new( attrType, attrValue,
1213 attrValueEncoding );
1214 if ( ava == NULL ) {
1215 rc = LDAP_NO_MEMORY;
1219 rdn = ldapava_append_to_rdn( newRDN, ava );
1220 if ( rdn == NULL ) {
1221 rc = LDAP_NO_MEMORY;
1227 * if we got an AVA separator ('+', or ',' for DCE )
1228 * we expect a new AVA for this RDN; otherwise
1229 * we add the RDN to the DN
1231 switch ( LDAP_DN_FORMAT( flags ) ) {
1232 case LDAP_DN_FORMAT_LDAP:
1233 case LDAP_DN_FORMAT_LDAPV3:
1234 case LDAP_DN_FORMAT_LDAPV2:
1235 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1240 case LDAP_DN_FORMAT_DCE:
1241 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1249 * the RDN is over, phew
1256 /* they should have been used in an AVA */
1272 /* They are set to NULL after they're used in an AVA */
1274 ber_bvfree( attrType );
1278 ber_bvfree( attrValue );
1282 ldap_rdnfree( newRDN );
1288 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n",
1296 * reads in a UTF-8 string value, unescaping stuff:
1297 * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1298 * '\' + HEXPAIR(p) -> unhex(p)
1301 str2strval( const char *str, struct berval **val, const char **next, unsigned flags, unsigned *retFlags )
1303 const char *p, *startPos, *endPos = NULL;
1304 ber_len_t len, escapes, unescapes;
1313 for ( startPos = p = str, escapes = 0, unescapes = 0; p[ 0 ]; p++ ) {
1314 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1316 if ( p[ 0 ] == '\0' ) {
1319 if ( ( p == startPos + 1 && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1320 || ( LDAP_DN_VALUE_END( p[ 1 ] ) && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
1321 || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1326 if ( LDAP_DN_HEXPAIR( p ) ) {
1329 hexstr2bin( p, &c );
1332 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1335 * we assume the string is UTF-8
1337 *retFlags = LDAP_AVA_NONPRINTABLE;
1344 if ( LDAP_DN_PEDANTIC & flags ) {
1348 * FIXME: we allow escaping
1349 * of chars that don't need
1350 * to and do not belong to
1351 * HEXDIGITS (we also allow
1352 * single hexdigit; maybe we
1357 } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) )
1358 || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1361 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1363 * FIXME: maybe we can add
1364 * escapes if not pedantic?
1371 * we do allow unescaped spaces at the end
1372 * of the value only in non-pedantic mode
1374 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1375 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1376 if ( flags & LDAP_DN_PEDANTIC ) {
1380 /* strip trailing (unescaped) spaces */
1381 for ( endPos = p - 1;
1382 endPos > startPos + 1 &&
1383 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1384 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1391 * FIXME: test memory?
1393 len = ( endPos ? endPos : p ) - startPos - escapes - unescapes;
1394 *val = LDAP_MALLOC( sizeof( struct berval ) );
1395 ( *val )->bv_len = len;
1397 if ( escapes == 0 && unescapes == 0 ) {
1398 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1403 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1404 for ( s = 0, d = 0; d < len; ) {
1405 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1407 if ( ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( startPos[ s ] ) )
1408 || ( s == len - 1 && LDAP_DN_NEEDESCAPE_TRAIL( startPos[ s ] ) )
1409 || LDAP_DN_NEEDESCAPE( startPos[ s ] ) ) {
1410 ( *val )->bv_val[ d++ ] =
1413 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1416 hexstr2bin( &startPos[ s ], &c );
1417 ( *val )->bv_val[ d++ ] = c;
1422 * we allow escaping of chars
1423 * that do not need to
1425 ( *val )->bv_val[ d++ ] =
1430 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1434 ( *val )->bv_val[ d ] = '\0';
1435 assert( strlen( ( *val )->bv_val ) == len );
1445 DCE2strval( const char *str, struct berval **val, const char **next, unsigned flags )
1447 const char *p, *startPos, *endPos = NULL;
1448 ber_len_t len, escapes;
1457 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1458 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1460 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1467 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1472 * FIXME: can we accept anything else? I guess we need
1473 * to stop if a value is not legal
1478 * (unescaped) trailing spaces are trimmed must be silently ignored;
1481 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1482 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1483 if ( flags & LDAP_DN_PEDANTIC ) {
1487 /* strip trailing (unescaped) spaces */
1488 for ( endPos = p - 1;
1489 endPos > startPos + 1 &&
1490 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1491 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1498 len = ( endPos ? endPos : p ) - startPos - escapes;
1499 *val = LDAP_MALLOC( sizeof( struct berval ) );
1500 ( *val )->bv_len = len;
1501 if ( escapes == 0 ){
1502 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1507 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1508 for ( s = 0, d = 0; d < len; ) {
1510 * This point is reached only if escapes
1511 * are properly used, so all we need to
1514 if ( LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1518 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1520 ( *val )->bv_val[ d ] = '\0';
1521 assert( strlen( ( *val )->bv_val ) == len );
1530 IA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1532 const char *p, *startPos, *endPos = NULL;
1533 ber_len_t len, escapes;
1546 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1547 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1549 if ( p[ 0 ] == '\0' ) {
1553 if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1554 && ( LDAP_DN_PEDANTIC & flags ) ) {
1559 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1564 * FIXME: can we accept anything else? I guess we need
1565 * to stop if a value is not legal
1569 /* strip trailing (unescaped) spaces */
1571 endPos > startPos + 1 &&
1572 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1573 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1578 *val = LDAP_MALLOC( sizeof( struct berval ) );
1579 len = ( endPos ? endPos : p ) - startPos - escapes;
1580 ( *val )->bv_len = len;
1581 if ( escapes == 0 ) {
1582 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1587 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1588 for ( s = 0, d = 0; d < len; ) {
1589 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1592 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1594 ( *val )->bv_val[ d ] = '\0';
1595 assert( strlen( ( *val )->bv_val ) == len );
1603 quotedIA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1605 const char *p, *startPos, *endPos = NULL;
1607 unsigned escapes = 0;
1616 /* initial quote already eaten */
1617 for ( startPos = p = str; p[ 0 ]; p++ ) {
1619 * According to RFC 1779, the quoted value can
1620 * contain escaped as well as unescaped special values;
1621 * as a consequence we tolerate escaped values
1622 * (e.g. '"\,"' -> '\,') and escape unescaped specials
1623 * (e.g. '","' -> '\,').
1625 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1626 if ( p[ 1 ] == '\0' ) {
1631 if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1632 && ( LDAP_DN_PEDANTIC & flags ) ) {
1634 * do we allow to escape normal chars?
1635 * LDAPv2 does not allow any mechanism
1636 * for escaping chars with '\' and hex
1643 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1645 /* eat closing quotes */
1651 * FIXME: can we accept anything else? I guess we need
1652 * to stop if a value is not legal
1656 if ( endPos == NULL ) {
1660 /* Strip trailing (unescaped) spaces */
1661 for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1665 len = endPos - startPos - escapes;
1667 *val = LDAP_MALLOC( sizeof( struct berval ) );
1668 ( *val )->bv_len = len;
1669 if ( escapes == 0 ) {
1670 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1675 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1676 ( *val )->bv_len = len;
1678 for ( s = d = 0; d < len; ) {
1679 if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1682 ( *val )->bv_val[ d++ ] = str[ s++ ];
1684 ( *val )->bv_val[ d ] = '\0';
1685 assert( strlen( ( *val )->bv_val ) == len );
1694 hexstr2bin( const char *str, char *c )
1704 if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1710 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) ) {
1717 if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1723 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) ) {
1724 *c += c2 - 'a' + 10;
1732 hexstr2binval( const char *str, struct berval **val, const char **next, unsigned flags )
1734 const char *p, *startPos, *endPos = NULL;
1745 for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1746 switch ( LDAP_DN_FORMAT( flags ) ) {
1747 case LDAP_DN_FORMAT_LDAPV3:
1748 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1753 case LDAP_DN_FORMAT_LDAP:
1754 case LDAP_DN_FORMAT_LDAPV2:
1755 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1760 case LDAP_DN_FORMAT_DCE:
1761 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1767 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1768 if ( flags & LDAP_DN_PEDANTIC ) {
1773 for ( ; p[ 0 ]; p++ ) {
1774 switch ( LDAP_DN_FORMAT( flags ) ) {
1775 case LDAP_DN_FORMAT_LDAPV3:
1776 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1781 case LDAP_DN_FORMAT_LDAP:
1782 case LDAP_DN_FORMAT_LDAPV2:
1783 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1788 case LDAP_DN_FORMAT_DCE:
1789 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1798 if ( !LDAP_DN_HEXPAIR( p ) ) {
1805 len = ( ( endPos ? endPos : p ) - startPos ) / 2;
1807 assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
1809 *val = LDAP_MALLOC( sizeof( struct berval ) );
1810 if ( *val == NULL ) {
1811 return( LDAP_NO_MEMORY );
1814 ( *val )->bv_len = len;
1815 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1816 if ( ( *val )->bv_val == NULL ) {
1818 return( LDAP_NO_MEMORY );
1821 for ( s = 0, d = 0; d < len; s += 2, d++ ) {
1824 hexstr2bin( &startPos[ s ], &c );
1826 ( *val )->bv_val[ d ] = c;
1829 ( *val )->bv_val[ d ] = '\0';
1836 * convert a byte in a hexadecimal pair
1839 byte2hexpair( const char *val, char *pair )
1841 static const char hexdig[] = "0123456789abcdef";
1847 * we assume the string has enough room for the hex encoding
1851 pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
1852 pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
1858 * convert a binary value in hexadecimal pairs
1861 binval2hexstr( struct berval *val, char *str )
1868 if ( val->bv_len == 0 ) {
1873 * we assume the string has enough room for the hex encoding
1877 for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
1878 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1885 * Length of the string representation, accounting for escaped hex
1889 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
1891 ber_len_t l, cl = 1;
1893 int escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3;
1899 if ( val->bv_len == 0 ) {
1903 for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
1904 cl = ldap_utf8_charlen( p );
1906 /* illegal utf-8 char! */
1909 } else if ( cl > 1 ) {
1912 for ( cnt = 1; cnt < cl; cnt++ ) {
1913 if ( ( p[ cnt ] & 0x80 ) == 0x00 ) {
1917 l += escaped_byte_len * cl;
1920 * there might be some chars we want to escape in form
1921 * of a couple of hexdigits for optimization purposes
1923 } else if ( LDAP_DN_WILLESCAPE( flags, p[ 0 ] ) ) {
1926 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
1927 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1928 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
1942 * convert to string representation, escaping with hex the UTF-8 stuff;
1943 * assume the destination has enough room for escaping
1946 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
1948 ber_len_t s, d, end;
1954 if ( val->bv_len == 0 ) {
1960 * we assume the string has enough room for the hex encoding
1963 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
1964 ber_len_t cl = ldap_utf8_charlen( &val->bv_val[ s ] );
1967 * there might be some chars we want to escape in form
1968 * of a couple of hexdigits for optimization purposes
1970 if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) )
1971 || LDAP_DN_WILLESCAPE( flags, val->bv_val[ s ] ) ) {
1974 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1979 } else if ( cl > 1 ) {
1981 str[ d++ ] = val->bv_val[ s++ ];
1985 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
1986 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
1987 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
1990 str[ d++ ] = val->bv_val[ s++ ];
2000 * Length of the IA5 string representation (no UTF-8 allowed)
2003 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
2012 if ( val->bv_len == 0 ) {
2016 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2018 * Turn value into a binary encoded BER
2023 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2024 if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2025 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2026 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2041 * convert to string representation (np UTF-8)
2042 * assume the destination has enough room for escaping
2045 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2047 ber_len_t s, d, end;
2053 if ( val->bv_len == 0 ) {
2058 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2060 * Turn value into a binary encoded BER
2067 * we assume the string has enough room for the hex encoding
2071 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2072 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2073 || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2074 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2077 str[ d++ ] = val->bv_val[ s++ ];
2087 * Length of the (supposedly) DCE string representation,
2088 * accounting for escaped hex of UTF-8 chars
2091 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2100 if ( val->bv_len == 0 ) {
2104 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2106 * FIXME: Turn the value into a binary encoded BER?
2111 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2112 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2127 * convert to (supposedly) DCE string representation,
2128 * escaping with hex the UTF-8 stuff;
2129 * assume the destination has enough room for escaping
2132 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2140 if ( val->bv_len == 0 ) {
2145 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2147 * FIXME: Turn the value into a binary encoded BER?
2155 * we assume the string has enough room for the hex encoding
2159 for ( s = 0, d = 0; s < val->bv_len; ) {
2160 if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2163 str[ d++ ] = val->bv_val[ s++ ];
2173 * Length of the (supposedly) AD canonical string representation,
2174 * accounting for escaped hex of UTF-8 chars
2177 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2186 if ( val->bv_len == 0 ) {
2190 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2192 * FIXME: Turn the value into a binary encoded BER?
2197 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2198 if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2213 * convert to (supposedly) AD string representation,
2214 * escaping with hex the UTF-8 stuff;
2215 * assume the destination has enough room for escaping
2218 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2226 if ( val->bv_len == 0 ) {
2231 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2233 * FIXME: Turn the value into a binary encoded BER?
2241 * we assume the string has enough room for the hex encoding
2245 for ( s = 0, d = 0; s < val->bv_len; ) {
2246 if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2249 str[ d++ ] = val->bv_val[ s++ ];
2259 * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2260 * the forst part of the AD representation of the DN is written in DNS
2261 * form, i.e. dot separated domain name components (as suggested
2262 * by Luke Howard, http://www.padl.com/~lukeh)
2265 dn2domain( LDAPDN *dn, char *str, int *iRDN )
2268 int domain = 0, first = 1;
2269 ber_len_t l = 1; /* we move the null also */
2271 /* we are guaranteed there's enough memory in str */
2277 assert( *iRDN > 0 );
2279 for ( i = *iRDN; i >= 0; i-- ) {
2283 assert( dn[ i ][ 0 ] );
2286 assert( rdn[ 0 ][ 0 ] );
2287 ava = rdn[ 0 ][ 0 ];
2289 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2297 AC_MEMCPY( str, ava->la_value->bv_val,
2298 ava->la_value->bv_len + 1);
2299 l += ava->la_value->bv_len;
2302 AC_MEMCPY( str + ava->la_value->bv_len + 1, str, l);
2303 AC_MEMCPY( str, ava->la_value->bv_val,
2304 ava->la_value->bv_len );
2305 str[ ava->la_value->bv_len ] = '.';
2306 l += ava->la_value->bv_len + 1;
2316 rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
2317 int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2324 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2325 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2327 /* len(type) + '=' + '+' | ',' */
2328 l += ava->la_attr->bv_len + 2;
2330 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2331 /* octothorpe + twice the length */
2332 l += 1 + 2 * ava->la_value->bv_len;
2336 unsigned f = flags | ava->la_flags;
2338 if ( ( *s2l )( ava->la_value, f, &vl ) ) {
2351 rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
2352 int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2357 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2358 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2360 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2361 ava->la_attr->bv_len );
2362 l += ava->la_attr->bv_len;
2366 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2368 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2371 l += 2 * ava->la_value->bv_len;
2375 unsigned f = flags | ava->la_flags;
2377 if ( ( *s2s )( ava->la_value, &str[ l ], f, &vl ) ) {
2382 str[ l++ ] = ( rdn[ iAVA + 1 ] ? '+' : ',' );
2391 rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2398 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2399 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2401 /* len(type) + '=' + ',' | '/' */
2402 l += ava->la_attr->bv_len + 2;
2404 switch ( ava->la_flags ) {
2405 case LDAP_AVA_BINARY:
2406 /* octothorpe + twice the length */
2407 l += 1 + 2 * ava->la_value->bv_len;
2410 case LDAP_AVA_STRING: {
2412 unsigned f = flags | ava->la_flags;
2414 if ( strval2DCEstrlen( ava->la_value, f, &vl ) ) {
2432 rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2437 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2438 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2443 str[ l++ ] = ( iAVA ? ',' : '/' );
2446 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2447 ava->la_attr->bv_len );
2448 l += ava->la_attr->bv_len;
2452 switch ( ava->la_flags ) {
2453 case LDAP_AVA_BINARY:
2455 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2458 l += 2 * ava->la_value->bv_len;
2461 case LDAP_AVA_STRING: {
2463 unsigned f = flags | ava->la_flags;
2465 if ( strval2DCEstr( ava->la_value, &str[ l ], f, &vl ) ) {
2483 rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2493 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2494 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2497 l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
2499 /* FIXME: are binary values allowed in UFN? */
2500 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2501 /* octothorpe + twice the value */
2502 l += 1 + 2 * ava->la_value->bv_len;
2506 unsigned f = flags | ava->la_flags;
2508 if ( strval2strlen( ava->la_value, f, &vl ) ) {
2521 rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
2526 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2527 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2529 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2531 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2534 l += 2 * ava->la_value->bv_len;
2538 unsigned f = flags | ava->la_flags;
2540 if ( strval2str( ava->la_value, &str[ l ], f, &vl ) ) {
2546 if ( rdn[ iAVA + 1 ]) {
2547 AC_MEMCPY( &str[ l ], " + ", 3 );
2551 AC_MEMCPY( &str[ l ], ", ", 2 );
2562 rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2572 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2573 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2578 /* FIXME: are binary values allowed in UFN? */
2579 switch ( ava->la_flags ) {
2580 case LDAP_AVA_BINARY:
2581 /* octothorpe + twice the value */
2582 l += 1 + 2 * ava->la_value->bv_len;
2585 case LDAP_AVA_STRING: {
2587 unsigned f = flags | ava->la_flags;
2589 if ( strval2ADstrlen( ava->la_value, f, &vl ) ) {
2607 rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2612 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2613 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2618 str[ l++ ] = ( iAVA ? ',' : '/' );
2621 switch ( ava->la_flags ) {
2622 case LDAP_AVA_BINARY:
2624 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2627 l += 2 * ava->la_value->bv_len;
2630 case LDAP_AVA_STRING: {
2632 unsigned f = flags | ava->la_flags;
2634 if ( strval2ADstr( ava->la_value, &str[ l ], f, &vl ) ) {
2654 * Returns in str a string representation of rdn based on flags.
2655 * There is some duplication of code between this and ldap_dn2str;
2656 * this is wanted to reduce the allocation of temporary buffers.
2659 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2666 if ( rdn == NULL ) {
2667 *str = LDAP_STRDUP( "" );
2668 return( LDAP_SUCCESS );
2672 * This routine wastes "back" bytes at the end of the string
2676 switch ( LDAP_DN_FORMAT( flags ) ) {
2677 case LDAP_DN_FORMAT_LDAPV3:
2678 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2679 return( LDAP_OTHER );
2683 case LDAP_DN_FORMAT_LDAPV2:
2684 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2685 return( LDAP_OTHER );
2689 case LDAP_DN_FORMAT_UFN:
2690 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2691 return( LDAP_OTHER );
2695 case LDAP_DN_FORMAT_DCE:
2696 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2697 return( LDAP_OTHER );
2701 case LDAP_DN_FORMAT_AD_CANONICAL:
2702 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2703 return( LDAP_OTHER );
2708 return( LDAP_INVALID_DN_SYNTAX );
2711 *str = LDAP_MALLOC( l + 1 );
2713 switch ( LDAP_DN_FORMAT( flags ) ) {
2714 case LDAP_DN_FORMAT_LDAPV3:
2715 rc = rdn2str( rdn, *str, flags, &l, strval2str );
2719 case LDAP_DN_FORMAT_LDAPV2:
2720 rc = rdn2str( rdn, *str, flags, &l, strval2IA5str );
2724 case LDAP_DN_FORMAT_UFN:
2725 rc = rdn2UFNstr( rdn, *str, flags, &l );
2729 case LDAP_DN_FORMAT_DCE:
2730 rc = rdn2DCEstr( rdn, *str, flags, &l, 1 );
2734 case LDAP_DN_FORMAT_AD_CANONICAL:
2735 rc = rdn2ADstr( rdn, *str, flags, &l, 1 );
2740 /* need at least one of the previous */
2741 return( LDAP_OTHER );
2745 ldap_memfree( *str );
2746 return( LDAP_OTHER );
2749 ( *str )[ l - back ] = '\0';
2751 return( LDAP_SUCCESS );
2755 * Very bulk implementation; many optimizations can be performed
2756 * - a NULL dn results in an empty string ""
2759 * a) what do we do if a UTF-8 string must be converted in LDAPv2?
2760 * we must encode it in binary form ('#' + HEXPAIRs)
2761 * b) does DCE/AD support UTF-8?
2762 * no clue; don't think so.
2763 * c) what do we do when binary values must be converted in UTF/DCE/AD?
2764 * use binary encoded BER
2766 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
2769 int rc = LDAP_OTHER;
2772 /* stringifying helpers for LDAPv3/LDAPv2 */
2773 int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2774 int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2778 Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2str(%u)\n%s%s", flags, "", "" );
2783 * a null dn means an empty dn string
2784 * FIXME: better raise an error?
2787 *str = LDAP_STRDUP( "" );
2788 return( LDAP_SUCCESS );
2791 switch ( LDAP_DN_FORMAT( flags ) ) {
2792 case LDAP_DN_FORMAT_LDAPV3:
2793 sv2l = strval2strlen;
2797 case LDAP_DN_FORMAT_LDAPV2:
2798 sv2l = strval2IA5strlen;
2799 sv2s = strval2IA5str;
2802 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2804 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2806 if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
2807 goto return_results;
2813 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2814 rc = LDAP_NO_MEMORY;
2818 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
2820 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2822 if ( rdn2str( rdn, &( *str )[ l ], flags,
2826 goto return_results;
2834 * trim the last ',' (the allocated memory
2835 * is one byte longer than required)
2837 ( *str )[ len - 1 ] = '\0';
2842 case LDAP_DN_FORMAT_UFN: {
2845 * FIXME: quoting from RFC 1781:
2847 To take a distinguished name, and generate a name of this format with
2848 attribute types omitted, the following steps are followed.
2850 1. If the first attribute is of type CommonName, the type may be
2853 2. If the last attribute is of type Country, the type may be
2856 3. If the last attribute is of type Country, the last
2857 Organisation attribute may have the type omitted.
2859 4. All attributes of type OrganisationalUnit may have the type
2860 omitted, unless they are after an Organisation attribute or
2861 the first attribute is of type OrganisationalUnit.
2863 * this should be the pedantic implementation.
2865 * Here the standard implementation reflects
2866 * the one historically provided by OpenLDAP
2867 * (and UMIch, I presume), with the variant
2868 * of spaces and plusses (' + ') separating
2871 * A non-standard but nice implementation could
2872 * be to turn the final "dc" attributes into a
2873 * dot-separated domain.
2875 * Other improvements could involve the use of
2876 * friendly country names and so.
2879 int leftmost_dc = -1;
2881 #endif /* DC_IN_UFN */
2883 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2885 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2887 if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
2888 goto return_results;
2893 if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
2894 if ( leftmost_dc == -1 ) {
2900 #endif /* DC_IN_UFN */
2903 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2904 rc = LDAP_NO_MEMORY;
2909 if ( leftmost_dc == -1 ) {
2910 #endif /* DC_IN_UFN */
2911 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
2913 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2915 if ( rdn2UFNstr( rdn, &( *str )[ l ],
2919 goto return_results;
2925 * trim the last ', ' (the allocated memory
2926 * is two bytes longer than required)
2928 ( *str )[ len - 2 ] = '\0';
2931 last_iRDN = iRDN - 1;
2933 for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
2935 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2937 if ( rdn2UFNstr( rdn, &( *str )[ l ],
2941 goto return_results;
2946 if ( !dn2domain( dn, &( *str )[ l ], &last_iRDN ) ) {
2949 goto return_results;
2952 /* the string is correctly terminated by dn2domain */
2954 #endif /* DC_IN_UFN */
2960 case LDAP_DN_FORMAT_DCE:
2962 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2964 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2966 if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
2967 goto return_results;
2973 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2974 rc = LDAP_NO_MEMORY;
2978 for ( l = 0; iRDN--; ) {
2980 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2982 if ( rdn2DCEstr( rdn, &( *str )[ l ], flags,
2986 goto return_results;
2993 ( *str )[ len ] = '\0';
2998 case LDAP_DN_FORMAT_AD_CANONICAL: {
3001 * Sort of UFN for DCE DNs: a slash ('/') separated
3002 * global->local DN with no types; strictly speaking,
3003 * the naming context should be a domain, which is
3004 * written in DNS-style, e.g. dot-deparated.
3008 * "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3012 * "microsoft.com/People/Bill,Gates"
3014 for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
3016 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3018 if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
3019 goto return_results;
3025 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3026 rc = LDAP_NO_MEMORY;
3031 if ( iRDN && dn2domain( dn, *str, &iRDN ) ) {
3032 for ( l = strlen( *str ); iRDN >= 0 ; iRDN-- ) {
3034 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3036 if ( rdn2ADstr( rdn, &( *str )[ l ],
3037 flags, &rdnl, 0 ) ) {
3040 goto return_results;
3049 * Strictly speaking, AD canonical requires
3050 * a DN to be in the form "..., dc=smtg",
3051 * i.e. terminated by a domain component
3053 if ( flags & LDAP_DN_PEDANTIC ) {
3056 rc = LDAP_INVALID_DN_SYNTAX;
3060 for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3062 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3064 if ( rdn2ADstr( rdn, &( *str )[ l ],
3065 flags, &rdnl, first ) ) {
3068 goto return_results;
3077 ( *str )[ len ] = '\0';
3084 return( LDAP_INVALID_DN_SYNTAX );
3088 Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2str(%s,%u)=%d\n", *str, flags, rc );