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 * ) * ( iRDN + 1 ) );
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;
180 unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
182 Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
185 * we assume this dn is made of one rdn only
187 if ( ldap_str2dn( rdn, &tmpDN, LDAP_DN_FORMAT_LDAP )
192 for ( iAVA = 0; tmpDN[ 0 ][ 0 ][ iAVA ]; iAVA++ ) {
193 ber_len_t l = 0, vl, al = 0;
194 char *str, **v = NULL;
195 LDAPAVA *ava = tmpDN[ 0 ][ 0 ][ iAVA ][ 0 ];
197 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iAVA ) );
203 if ( ava->la_flags == LDAP_AVA_BINARY ) {
204 vl = 1 + 2 * ava->la_value->bv_len;
207 if ( strval2strlen( ava->la_value,
208 ava->la_flags, &vl ) ) {
214 al = ava->la_attr->bv_len;
215 l = vl + ava->la_attr->bv_len + 1;
217 str = LDAP_MALLOC( l + 1 );
218 AC_MEMCPY( str, ava->la_attr->bv_val,
219 ava->la_attr->bv_len );
224 str = LDAP_MALLOC( l + 1 );
227 if ( ava->la_flags == LDAP_AVA_BINARY ) {
229 if ( binval2hexstr( ava->la_value, &str[ al ] ) ) {
234 if ( strval2str( ava->la_value, &str[ al ],
235 ava->la_flags, &vl ) ) {
241 values[ iAVA ] = str;
243 values[ iAVA ] = NULL;
245 ldap_dnfree( tmpDN );
250 LBER_VFREE( values );
251 ldap_dnfree( tmpDN );
256 ldap_dn2dcedn( LDAP_CONST char *dn )
260 Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
262 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_DCE );
268 ldap_dcedn2dn( LDAP_CONST char *dce )
272 Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
274 ( void )dn2dn( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
280 ldap_dn2ad_canonical( LDAP_CONST char *dn )
284 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
286 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP,
287 &out, LDAP_DN_FORMAT_AD_CANONICAL );
293 ldap_dn_normalize( const char *in, unsigned iflags, char **out, unsigned oflags )
297 Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );
299 return dn2dn( in, iflags, out, oflags);
303 * helper that changes the string representation of dnin
304 * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
307 * LDAP_DN_FORMAT_LDAP (rfc 2253 and ldapbis liberal,
308 * plus some rfc 1779)
309 * LDAP_DN_FORMAT_LDAPV3 (rfc 2253 and ldapbis)
310 * LDAP_DN_FORMAT_LDAPV2 (rfc 1779)
311 * LDAP_DN_FORMAT_DCE (?)
313 * fout can be any of the above except
314 * LDAP_DN_FORMAT_LDAP
316 * LDAP_DN_FORMAT_UFN (rfc 1781, partial and with extensions)
317 * LDAP_DN_FORMAT_AD_CANONICAL (?)
320 dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout )
323 LDAPDN *tmpDN = NULL;
329 if ( dnin == NULL ) {
330 return( LDAP_SUCCESS );
333 rc = ldap_str2dn( dnin , &tmpDN, fin );
334 if ( rc != LDAP_SUCCESS ) {
338 rc = ldap_dn2str( tmpDN, dnout, fout );
340 ldap_dnfree( tmpDN );
348 /* #define B4ATTRTYPE 0x0001 */
349 #define B4OIDATTRTYPE 0x0002
350 #define B4STRINGATTRTYPE 0x0003
352 #define B4AVAEQUALS 0x0100
353 #define B4AVASEP 0x0200
354 #define B4RDNSEP 0x0300
355 #define GOTAVA 0x0400
357 #define B4ATTRVALUE 0x0010
358 #define B4STRINGVALUE 0x0020
359 #define B4IA5VALUEQUOTED 0x0030
360 #define B4IA5VALUE 0x0040
361 #define B4BINARYVALUE 0x0050
363 /* Helpers (mostly from slapd.h; maybe it should be rewritten from this) */
364 #define LDAP_DN_ASCII_SPACE(c) \
365 ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
366 #define LDAP_DN_ASCII_LOWER(c) ( (c) >= 'a' && (c) <= 'z' )
367 #define LDAP_DN_ASCII_UPPER(c) ( (c) >= 'A' && (c) <= 'Z' )
368 #define LDAP_DN_ASCII_ALPHA(c) \
369 ( LDAP_DN_ASCII_LOWER(c) || LDAP_DN_ASCII_UPPER(c) )
370 #define LDAP_DN_ASCII_DIGIT(c) ( (c) >= '0' && (c) <= '9' )
371 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) ( (c) >= 'a' && (c) <= 'f' )
372 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) ( (c) >= 'A' && (c) <= 'F' )
373 #define LDAP_DN_ASCII_HEXDIGIT(c) \
374 ( LDAP_DN_ASCII_DIGIT(c) \
375 || LDAP_DN_ASCII_LCASE_HEXALPHA(c) \
376 || LDAP_DN_ASCII_UCASE_HEXALPHA(c) )
377 #define LDAP_DN_ASCII_ALNUM(c) \
378 ( LDAP_DN_ASCII_ALPHA(c) || LDAP_DN_ASCII_DIGIT(c) )
379 #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' )
382 #define LDAP_DN_OID_LEADCHAR(c) ( LDAP_DN_ASCII_DIGIT(c) )
383 #define LDAP_DN_DESC_LEADCHAR(c) ( LDAP_DN_ASCII_ALPHA(c) )
384 #define LDAP_DN_DESC_CHAR(c) ( LDAP_DN_ASCII_ALNUM(c) || (c) == '-' )
385 #define LDAP_DN_LANG_SEP(c) ( (c) == ';' )
386 #define LDAP_DN_ATTRDESC_CHAR(c) \
387 ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
389 /* special symbols */
390 #define LDAP_DN_AVA_EQUALS(c) ( (c) == '=' )
391 #define LDAP_DN_AVA_SEP(c) ( (c) == '+' )
392 #define LDAP_DN_RDN_SEP(c) ( (c) == ',' )
393 #define LDAP_DN_RDN_SEP_V2(c) ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
394 #define LDAP_DN_OCTOTHORPE(c) ( (c) == '#' )
395 #define LDAP_DN_QUOTES(c) ( (c) == '\"' )
396 #define LDAP_DN_ESCAPE(c) ( (c) == '\\' )
397 #define LDAP_DN_VALUE_END(c) \
398 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
399 #define LDAP_DN_NE(c) \
400 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
401 || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
402 #define LDAP_DN_NEEDESCAPE(c) \
403 ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
404 #define LDAP_DN_NEEDESCAPE_LEAD(c) \
405 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) )
406 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
407 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
408 #define LDAP_DN_WILLESCAPE_CHAR( c) \
409 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
410 #define LDAP_DN_IS_PRETTY( f ) ( (f) & LDAP_DN_PRETTY )
411 #define LDAP_DN_WILLESCAPE(f, c) \
412 ( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
415 #define LDAP_DN_VALUE_END_V2(c) \
416 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
418 #define LDAP_DN_V2_SPECIAL(c) \
419 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
420 || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
421 || LDAP_DN_OCTOTHORPE(c) )
422 #define LDAP_DN_V2_PAIR(c) \
423 ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
426 * DCE (mostly from Luke Howard and IBM implementation for AIX)
428 * From: "Application Development Guide - Directory Services" (FIXME: add link?)
429 * Here escapes and valid chars for GDS are considered; as soon as more
430 * specific info is found, the macros will be updated.
432 * Chars: 'a'-'z', 'A'-'Z', '0'-'9',
433 * '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
435 * Metachars: '/', ',', '=', '\'.
437 * the '\' is used to escape other metachars.
443 * Attribute types must start with alphabetic chars and can contain
444 * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
446 #define LDAP_DN_RDN_SEP_DCE(c) ( (c) == '/' )
447 #define LDAP_DN_AVA_SEP_DCE(c) ( (c) == ',' )
448 #define LDAP_DN_ESCAPE_DCE(c) ( LDAP_DN_ESCAPE(c) )
449 #define LDAP_DN_VALUE_END_DCE(c) \
450 ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
451 #define LDAP_DN_NEEDESCAPE_DCE(c) \
452 ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
455 #define LDAP_DN_RDN_SEP_AD(c) ( (c) == '/' )
456 #define LDAP_DN_ESCAPE_AD(c) ( LDAP_DN_ESCAPE(c) )
457 #define LDAP_DN_AVA_SEP_AD(c) ( (c) == ',' ) /* assume same as DCE */
458 #define LDAP_DN_VALUE_END_AD(c) \
459 ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
460 #define LDAP_DN_NEEDESCAPE_AD(c) \
461 ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
464 #define LDAP_DN_HEXPAIR(s) \
465 ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
466 #define LDAP_DC_ATTR "dc"
467 /* better look at the AttributeDescription? */
469 /* FIXME: no composite rdn or non-"dc" types, right?
470 * (what about "dc" in OID form?) */
471 /* FIXME: we do not allow binary values in domain, right? */
472 /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
473 #define LDAP_DN_IS_RDN_DC( rdn ) \
474 ( ( rdn ) && ( rdn )[ 0 ][ 0 ] && !( rdn )[ 1 ] \
475 && ( ( rdn )[ 0 ][ 0 ]->la_flags == LDAP_AVA_STRING ) \
476 && ! strcasecmp( ( rdn )[ 0 ][ 0 ]->la_attr->bv_val, LDAP_DC_ATTR ) )
478 /* Composite rules */
479 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
480 ( LDAP_DN_LDAPV2(f) \
481 || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
482 #define LDAP_DN_ALLOW_SPACES(f) \
483 ( LDAP_DN_LDAPV2(f) \
484 || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
485 #define LDAP_DN_LDAP(f) \
486 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
487 #define LDAP_DN_LDAPV3(f) \
488 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
489 #define LDAP_DN_LDAPV2(f) \
490 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
491 #define LDAP_DN_DCE(f) \
492 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
493 #define LDAP_DN_UFN(f) \
494 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
495 #define LDAP_DN_ADC(f) \
496 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
497 #define LDAP_DN_FORMAT(f) ( (f) & LDAP_DN_FORMAT_MASK )
500 * LDAPAVA helpers (will become part of the API for operations
501 * on structural representations of DNs).
504 ldapava_new( const struct berval *attr, const struct berval *val,
512 ava = LDAP_MALLOC( sizeof( LDAPAVA ) );
514 /* should we test it? */
519 ava->la_attr = ( struct berval * )attr;
520 ava->la_value = ( struct berval * )val;
521 ava->la_flags = flags;
523 ava->la_private = NULL;
529 ldap_avafree( LDAPAVA *ava )
534 /* ava's private must be freed by caller */
535 assert( ava->la_private != NULL );
538 ber_bvfree( ava->la_attr );
539 ber_bvfree( ava->la_value );
545 ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava )
553 for ( i = 0U; rdn[ i ]; i++ ) {
557 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
558 newRDN[ i ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
559 newRDN[ i ][ 0 ] = ava;
560 newRDN[ i + 1 ] = NULL;
566 ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where )
574 for ( i = 0U; rdn[ i ]; i++ ) {
580 /* assume "at end", which corresponds to
581 * ldapava_append_to_rdn */
584 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
586 /* data after insert point */
587 AC_MEMCPY( &newRDN[ where + 1 ], &newRDN[ where ],
588 ( i - where ) * sizeof( LDAPRDN * ) );
590 newRDN[ where ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
591 newRDN[ where ][ 0 ] = ava;
592 newRDN[ i + 1 ] = NULL;
598 ldap_rdnfree( LDAPRDN *rdn )
606 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
607 assert( rdn[ iAVA ][ 0 ] );
609 ldap_avafree( rdn[ iAVA ][ 0 ] );
616 ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn )
624 for ( i = 0U; dn[ i ]; i++ ) {
628 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
629 newDN[ i ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
630 newDN[ i ][ 0 ] = rdn;
631 newDN[ i + 1 ] = NULL;
637 ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where )
645 for ( i = 0U; dn[ i ]; i++ ) {
651 /* assume "at end", which corresponds to
652 * ldapava_append_to_dn */
655 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
657 /* data after insert point */
658 AC_MEMCPY( &newDN[ where + 1 ], &newDN[ where ],
659 ( i - where ) * sizeof( LDAPDN * ) );
661 newDN[ where ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
662 newDN[ where ][ 0 ] = rdn;
663 newDN[ i + 1 ] = NULL;
669 ldap_dnfree( LDAPDN *dn )
677 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
678 assert( dn[ iRDN ][ 0 ] );
680 ldap_rdnfree( dn[ iRDN ][ 0 ] );
687 * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
688 * into a structural representation of the DN, by separating attribute
689 * types and values encoded in the more appropriate form, which is
690 * string or OID for attribute types and binary form of the BER encoded
691 * value or Unicode string. Formats different from LDAPv3 are parsed
692 * according to their own rules and turned into the more appropriate
693 * form according to LDAPv3.
695 * NOTE: I realize the code is getting spaghettish; it is rather
696 * experimental and will hopefully turn into something more simple
697 * and readable as soon as it works as expected.
701 ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
704 int rc = LDAP_INVALID_DN_SYNTAX;
706 LDAPDN *newDN = NULL;
707 LDAPRDN *newRDN = NULL;
712 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );
716 switch ( LDAP_DN_FORMAT( flags ) ) {
717 case LDAP_DN_FORMAT_LDAP:
718 case LDAP_DN_FORMAT_LDAPV3:
719 case LDAP_DN_FORMAT_LDAPV2:
720 case LDAP_DN_FORMAT_DCE:
723 /* unsupported in str2dn */
724 case LDAP_DN_FORMAT_UFN:
725 case LDAP_DN_FORMAT_AD_CANONICAL:
726 return( LDAP_INVALID_DN_SYNTAX );
729 return( LDAP_OTHER );
732 if ( str[ 0 ] == '\0' ) {
733 return( LDAP_SUCCESS );
737 if ( LDAP_DN_DCE( flags ) ) {
740 * (from Luke Howard: thnx) A RDN separator is required
741 * at the beginning of an (absolute) DN.
743 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
748 } else if ( LDAP_DN_LDAP( flags ) ) {
750 * if dn starts with '/' let's make it a DCE dn
752 if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
753 flags |= LDAP_DN_FORMAT_DCE;
758 for ( ; p[ 0 ]; p++ ) {
762 err = ldap_str2rdn( p, &newRDN, &p, flags );
763 if ( err != LDAP_SUCCESS ) {
768 * We expect a rdn separator
771 switch ( LDAP_DN_FORMAT( flags ) ) {
772 case LDAP_DN_FORMAT_LDAPV3:
773 if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
779 case LDAP_DN_FORMAT_LDAP:
780 case LDAP_DN_FORMAT_LDAPV2:
781 if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
787 case LDAP_DN_FORMAT_DCE:
788 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
797 if ( LDAP_DN_DCE( flags ) ) {
798 /* add in reversed order */
799 dn = ldapava_insert_into_dn( newDN, newRDN, 0 );
801 dn = ldapava_append_to_dn( newDN, newRDN );
812 if ( p[ 0 ] == '\0' ) {
815 * the DN is over, phew
824 ldap_rdnfree( newRDN );
828 ldap_dnfree( newDN );
834 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
843 * Parses a relative DN according to flags up to a rdn separator
844 * or to the end of str.
845 * Returns the rdn and a pointer to the string continuation, which
846 * corresponds to the rdn separator or to '\0' in case the string is over.
849 ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
853 int rc = LDAP_INVALID_DN_SYNTAX;
854 int attrTypeEncoding = LDAP_AVA_STRING,
855 attrValueEncoding = LDAP_AVA_STRING;
857 struct berval *attrType = NULL;
858 struct berval *attrValue = NULL;
860 LDAPRDN *newRDN = NULL;
866 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );
871 switch ( LDAP_DN_FORMAT( flags ) ) {
872 case LDAP_DN_FORMAT_LDAP:
873 case LDAP_DN_FORMAT_LDAPV3:
874 case LDAP_DN_FORMAT_LDAPV2:
875 case LDAP_DN_FORMAT_DCE:
878 /* unsupported in str2dn */
879 case LDAP_DN_FORMAT_UFN:
880 case LDAP_DN_FORMAT_AD_CANONICAL:
881 return( LDAP_INVALID_DN_SYNTAX );
884 return( LDAP_OTHER );
887 if ( str[ 0 ] == '\0' ) {
888 return( LDAP_SUCCESS );
892 for ( ; p[ 0 ] || state == GOTAVA; ) {
895 * The parser in principle advances one token a time,
896 * or toggles state if preferable.
901 * an AttributeType can be encoded as:
902 * - its string representation; in detail, implementations
903 * MUST recognize AttributeType string type names listed
904 * in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
905 * MAY recognize other names.
906 * - its numeric OID (a dotted decimal string); in detail
907 * RFC 2253 asserts that ``Implementations MUST allow
908 * an oid in the attribute type to be prefixed by one
909 * of the character strings "oid." or "OID."''. As soon
910 * as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253
911 * I'm not sure whether this is required or not any
912 * longer; to be liberal, we still implement it.
915 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
916 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
923 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
924 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
929 /* whitespace is allowed (and trimmed) */
931 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
936 /* error: we expected an AVA */
942 if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
943 state = B4OIDATTRTYPE;
947 /* else must be alpha */
948 if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
952 /* LDAPv2 "oid." prefix */
953 if ( LDAP_DN_LDAPV2( flags ) ) {
955 * to be overly pedantic, we only accept
958 if ( flags & LDAP_DN_PEDANTIC ) {
959 if ( !strncmp( p, "OID.", 4 )
960 || !strncmp( p, "oid.", 4 ) ) {
962 state = B4OIDATTRTYPE;
966 if ( !strncasecmp( p, "oid.", 4 ) ) {
968 state = B4OIDATTRTYPE;
974 state = B4STRINGATTRTYPE;
977 case B4OIDATTRTYPE: {
978 int err = LDAP_SUCCESS;
981 type = parse_numericoid( &p, &err, 0 );
982 if ( type == NULL ) {
985 attrType = LDAP_MALLOC( sizeof( struct berval ) );
986 if ( attrType== NULL ) {
990 attrType->bv_val = type;
991 attrType->bv_len = strlen( type );
992 attrTypeEncoding = LDAP_AVA_BINARY;
998 case B4STRINGATTRTYPE: {
999 const char *startPos, *endPos = NULL;
1003 * the starting char has been found to be
1004 * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
1005 * FIXME: DCE attr types seem to have a more
1006 * restrictive syntax (no '-' ...)
1008 for ( startPos = p++; p[ 0 ]; p++ ) {
1009 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
1013 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
1016 * RFC 2253 does not explicitly
1017 * allow lang extensions to attribute
1020 if ( flags & LDAP_DN_PEDANTIC ) {
1025 * we trim ';' and following lang
1026 * and so from attribute types
1029 for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
1030 || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
1038 len = ( endPos ? endPos : p ) - startPos;
1043 assert( attrType == NULL );
1044 attrType = LDAP_MALLOC( sizeof( struct berval ) );
1045 if ( attrType == NULL ) {
1046 rc = LDAP_NO_MEMORY;
1049 attrType->bv_val = LDAP_STRNDUP( startPos, len );
1050 if ( attrType->bv_val == NULL ) {
1051 rc = LDAP_NO_MEMORY;
1054 attrType->bv_len = len;
1055 attrTypeEncoding = LDAP_AVA_STRING;
1058 * here we need to decide whether to use it as is
1059 * or turn it in OID form; as a consequence, we
1060 * need to decide whether to binary encode the value
1063 state = B4AVAEQUALS;
1068 /* spaces may not be allowed */
1069 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1070 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1075 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1080 /* need equal sign */
1081 if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1086 /* spaces may not be allowed */
1087 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1088 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1093 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1099 * octothorpe means a BER encoded value will follow
1100 * FIXME: I don't think DCE will allow it
1102 if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1104 attrValueEncoding = LDAP_AVA_BINARY;
1105 state = B4BINARYVALUE;
1109 /* STRING value expected */
1112 * if we're pedantic, an attribute type in OID form
1113 * SHOULD imply a BER encoded attribute value; we
1114 * should at least issue a warning
1116 if ( ( flags & LDAP_DN_PEDANTIC )
1117 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1118 /* OID attrType SHOULD use binary encoding */
1122 attrValueEncoding = LDAP_AVA_STRING;
1125 * LDAPv2 allows the attribute value to be quoted;
1126 * also, IA5 values are expected, in principle
1128 if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1129 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1131 state = B4IA5VALUEQUOTED;
1135 if ( LDAP_DN_LDAPV2( flags ) ) {
1142 * here STRING means RFC 2253 string
1143 * FIXME: what about DCE strings?
1145 state = B4STRINGVALUE;
1149 if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
1157 switch ( LDAP_DN_FORMAT( flags ) ) {
1158 case LDAP_DN_FORMAT_LDAP:
1159 case LDAP_DN_FORMAT_LDAPV3:
1160 if ( str2strval( p, &attrValue, &p, flags,
1161 &attrValueEncoding ) ) {
1166 case LDAP_DN_FORMAT_DCE:
1167 if ( DCE2strval( p, &attrValue, &p, flags ) ) {
1180 if ( IA52strval( p, &attrValue, &p, flags ) ) {
1187 case B4IA5VALUEQUOTED:
1189 /* lead quote already stripped */
1190 if ( quotedIA52strval( p, &attrValue,
1204 * we accept empty values
1206 ava = ldapava_new( attrType, attrValue,
1207 attrValueEncoding );
1208 if ( ava == NULL ) {
1209 rc = LDAP_NO_MEMORY;
1213 rdn = ldapava_append_to_rdn( newRDN, ava );
1214 if ( rdn == NULL ) {
1215 rc = LDAP_NO_MEMORY;
1221 * if we got an AVA separator ('+', or ',' for DCE )
1222 * we expect a new AVA for this RDN; otherwise
1223 * we add the RDN to the DN
1225 switch ( LDAP_DN_FORMAT( flags ) ) {
1226 case LDAP_DN_FORMAT_LDAP:
1227 case LDAP_DN_FORMAT_LDAPV3:
1228 case LDAP_DN_FORMAT_LDAPV2:
1229 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1234 case LDAP_DN_FORMAT_DCE:
1235 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1243 * the RDN is over, phew
1250 /* they should have been used in an AVA */
1266 /* They are set to NULL after they're used in an AVA */
1268 ber_bvfree( attrType );
1272 ber_bvfree( attrValue );
1276 ldap_rdnfree( newRDN );
1282 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n",
1290 * reads in a UTF-8 string value, unescaping stuff:
1291 * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1292 * '\' + HEXPAIR(p) -> unhex(p)
1295 str2strval( const char *str, struct berval **val, const char **next, unsigned flags, unsigned *retFlags )
1297 const char *p, *startPos, *endPos = NULL;
1298 ber_len_t len, escapes, unescapes;
1307 for ( startPos = p = str, escapes = 0, unescapes = 0; p[ 0 ]; p++ ) {
1308 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1310 if ( p[ 0 ] == '\0' ) {
1313 if ( ( p == startPos + 1 && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1314 || ( LDAP_DN_VALUE_END( p[ 1 ] ) && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
1315 || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1320 if ( LDAP_DN_HEXPAIR( p ) ) {
1323 hexstr2bin( p, &c );
1326 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1329 * we assume the string is UTF-8
1331 *retFlags = LDAP_AVA_NONPRINTABLE;
1338 if ( LDAP_DN_PEDANTIC & flags ) {
1342 * FIXME: we allow escaping
1343 * of chars that don't need
1344 * to and do not belong to
1345 * HEXDIGITS (we also allow
1346 * single hexdigit; maybe we
1351 } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) )
1352 || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1355 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1357 * FIXME: maybe we can add
1358 * escapes if not pedantic?
1365 * we do allow unescaped spaces at the end
1366 * of the value only in non-pedantic mode
1368 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1369 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1370 if ( flags & LDAP_DN_PEDANTIC ) {
1374 /* strip trailing (unescaped) spaces */
1375 for ( endPos = p - 1;
1376 endPos > startPos + 1 &&
1377 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1378 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1385 * FIXME: test memory?
1387 len = ( endPos ? endPos : p ) - startPos - escapes - unescapes;
1388 *val = LDAP_MALLOC( sizeof( struct berval ) );
1389 ( *val )->bv_len = len;
1391 if ( escapes == 0 && unescapes == 0 ) {
1392 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1397 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1398 for ( s = 0, d = 0; d < len; ) {
1399 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1401 if ( ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( startPos[ s ] ) )
1402 || ( s == len - 1 && LDAP_DN_NEEDESCAPE_TRAIL( startPos[ s ] ) )
1403 || LDAP_DN_NEEDESCAPE( startPos[ s ] ) ) {
1404 ( *val )->bv_val[ d++ ] =
1407 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1410 hexstr2bin( &startPos[ s ], &c );
1411 ( *val )->bv_val[ d++ ] = c;
1416 * we allow escaping of chars
1417 * that do not need to
1419 ( *val )->bv_val[ d++ ] =
1424 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1428 ( *val )->bv_val[ d ] = '\0';
1429 assert( strlen( ( *val )->bv_val ) == len );
1439 DCE2strval( const char *str, struct berval **val, const char **next, unsigned flags )
1441 const char *p, *startPos, *endPos = NULL;
1442 ber_len_t len, escapes;
1451 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1452 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1454 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1461 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1466 * FIXME: can we accept anything else? I guess we need
1467 * to stop if a value is not legal
1472 * (unescaped) trailing spaces are trimmed must be silently ignored;
1475 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1476 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1477 if ( flags & LDAP_DN_PEDANTIC ) {
1481 /* strip trailing (unescaped) spaces */
1482 for ( endPos = p - 1;
1483 endPos > startPos + 1 &&
1484 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1485 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1492 len = ( endPos ? endPos : p ) - startPos - escapes;
1493 *val = LDAP_MALLOC( sizeof( struct berval ) );
1494 ( *val )->bv_len = len;
1495 if ( escapes == 0 ){
1496 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1501 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1502 for ( s = 0, d = 0; d < len; ) {
1504 * This point is reached only if escapes
1505 * are properly used, so all we need to
1508 if ( LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1512 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1514 ( *val )->bv_val[ d ] = '\0';
1515 assert( strlen( ( *val )->bv_val ) == len );
1524 IA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1526 const char *p, *startPos, *endPos = NULL;
1527 ber_len_t len, escapes;
1540 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1541 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1543 if ( p[ 0 ] == '\0' ) {
1547 if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1548 && ( LDAP_DN_PEDANTIC & flags ) ) {
1553 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1558 * FIXME: can we accept anything else? I guess we need
1559 * to stop if a value is not legal
1563 /* strip trailing (unescaped) spaces */
1565 endPos > startPos + 1 &&
1566 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1567 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1572 *val = LDAP_MALLOC( sizeof( struct berval ) );
1573 len = ( endPos ? endPos : p ) - startPos - escapes;
1574 ( *val )->bv_len = len;
1575 if ( escapes == 0 ) {
1576 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1581 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1582 for ( s = 0, d = 0; d < len; ) {
1583 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1586 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1588 ( *val )->bv_val[ d ] = '\0';
1589 assert( strlen( ( *val )->bv_val ) == len );
1597 quotedIA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1599 const char *p, *startPos, *endPos = NULL;
1601 unsigned escapes = 0;
1610 /* initial quote already eaten */
1611 for ( startPos = p = str; p[ 0 ]; p++ ) {
1613 * According to RFC 1779, the quoted value can
1614 * contain escaped as well as unescaped special values;
1615 * as a consequence we tolerate escaped values
1616 * (e.g. '"\,"' -> '\,') and escape unescaped specials
1617 * (e.g. '","' -> '\,').
1619 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1620 if ( p[ 1 ] == '\0' ) {
1625 if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1626 && ( LDAP_DN_PEDANTIC & flags ) ) {
1628 * do we allow to escape normal chars?
1629 * LDAPv2 does not allow any mechanism
1630 * for escaping chars with '\' and hex
1637 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1639 /* eat closing quotes */
1645 * FIXME: can we accept anything else? I guess we need
1646 * to stop if a value is not legal
1650 if ( endPos == NULL ) {
1654 /* Strip trailing (unescaped) spaces */
1655 for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1659 len = endPos - startPos - escapes;
1661 *val = LDAP_MALLOC( sizeof( struct berval ) );
1662 ( *val )->bv_len = len;
1663 if ( escapes == 0 ) {
1664 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1669 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1670 ( *val )->bv_len = len;
1672 for ( s = d = 0; d < len; ) {
1673 if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1676 ( *val )->bv_val[ d++ ] = str[ s++ ];
1678 ( *val )->bv_val[ d ] = '\0';
1679 assert( strlen( ( *val )->bv_val ) == len );
1688 hexstr2bin( const char *str, char *c )
1698 if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1704 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) ) {
1711 if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1717 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) ) {
1718 *c += c2 - 'a' + 10;
1726 hexstr2binval( const char *str, struct berval **val, const char **next, unsigned flags )
1728 const char *p, *startPos, *endPos = NULL;
1739 for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1740 switch ( LDAP_DN_FORMAT( flags ) ) {
1741 case LDAP_DN_FORMAT_LDAPV3:
1742 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1747 case LDAP_DN_FORMAT_LDAP:
1748 case LDAP_DN_FORMAT_LDAPV2:
1749 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1754 case LDAP_DN_FORMAT_DCE:
1755 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1761 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1762 if ( flags & LDAP_DN_PEDANTIC ) {
1767 for ( ; p[ 0 ]; p++ ) {
1768 switch ( LDAP_DN_FORMAT( flags ) ) {
1769 case LDAP_DN_FORMAT_LDAPV3:
1770 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1775 case LDAP_DN_FORMAT_LDAP:
1776 case LDAP_DN_FORMAT_LDAPV2:
1777 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1782 case LDAP_DN_FORMAT_DCE:
1783 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1792 if ( !LDAP_DN_HEXPAIR( p ) ) {
1799 len = ( ( endPos ? endPos : p ) - startPos ) / 2;
1801 assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
1803 *val = LDAP_MALLOC( sizeof( struct berval ) );
1804 if ( *val == NULL ) {
1805 return( LDAP_NO_MEMORY );
1808 ( *val )->bv_len = len;
1809 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1810 if ( ( *val )->bv_val == NULL ) {
1812 return( LDAP_NO_MEMORY );
1815 for ( s = 0, d = 0; d < len; s += 2, d++ ) {
1818 hexstr2bin( &startPos[ s ], &c );
1820 ( *val )->bv_val[ d ] = c;
1823 ( *val )->bv_val[ d ] = '\0';
1830 * convert a byte in a hexadecimal pair
1833 byte2hexpair( const char *val, char *pair )
1835 static const char hexdig[] = "0123456789abcdef";
1841 * we assume the string has enough room for the hex encoding
1845 pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
1846 pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
1852 * convert a binary value in hexadecimal pairs
1855 binval2hexstr( struct berval *val, char *str )
1862 if ( val->bv_len == 0 ) {
1867 * we assume the string has enough room for the hex encoding
1871 for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
1872 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1879 * Length of the string representation, accounting for escaped hex
1883 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
1885 ber_len_t l, cl = 1;
1887 int escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3;
1893 if ( val->bv_len == 0 ) {
1897 for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
1898 cl = ldap_utf8_charlen( p );
1900 /* illegal utf-8 char! */
1903 } else if ( cl > 1 ) {
1906 for ( cnt = 1; cnt < cl; cnt++ ) {
1907 if ( ( p[ cnt ] & 0x80 ) == 0x00 ) {
1911 l += escaped_byte_len * cl;
1914 * there might be some chars we want to escape in form
1915 * of a couple of hexdigits for optimization purposes
1917 } else if ( LDAP_DN_WILLESCAPE( flags, p[ 0 ] ) ) {
1920 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
1921 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1922 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
1936 * convert to string representation, escaping with hex the UTF-8 stuff;
1937 * assume the destination has enough room for escaping
1940 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
1942 ber_len_t s, d, end;
1948 if ( val->bv_len == 0 ) {
1954 * we assume the string has enough room for the hex encoding
1957 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
1958 ber_len_t cl = ldap_utf8_charlen( &val->bv_val[ s ] );
1961 * there might be some chars we want to escape in form
1962 * of a couple of hexdigits for optimization purposes
1964 if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) )
1965 || LDAP_DN_WILLESCAPE( flags, val->bv_val[ s ] ) ) {
1968 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1973 } else if ( cl > 1 ) {
1975 str[ d++ ] = val->bv_val[ s++ ];
1979 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
1980 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
1981 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
1984 str[ d++ ] = val->bv_val[ s++ ];
1994 * Length of the IA5 string representation (no UTF-8 allowed)
1997 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
2006 if ( val->bv_len == 0 ) {
2010 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2012 * Turn value into a binary encoded BER
2017 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2018 if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2019 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2020 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2035 * convert to string representation (np UTF-8)
2036 * assume the destination has enough room for escaping
2039 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2041 ber_len_t s, d, end;
2047 if ( val->bv_len == 0 ) {
2052 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2054 * Turn value into a binary encoded BER
2061 * we assume the string has enough room for the hex encoding
2065 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2066 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2067 || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2068 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2071 str[ d++ ] = val->bv_val[ s++ ];
2081 * Length of the (supposedly) DCE string representation,
2082 * accounting for escaped hex of UTF-8 chars
2085 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2094 if ( val->bv_len == 0 ) {
2098 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2100 * FIXME: Turn the value into a binary encoded BER?
2105 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2106 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2121 * convert to (supposedly) DCE string representation,
2122 * escaping with hex the UTF-8 stuff;
2123 * assume the destination has enough room for escaping
2126 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2134 if ( val->bv_len == 0 ) {
2139 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2141 * FIXME: Turn the value into a binary encoded BER?
2149 * we assume the string has enough room for the hex encoding
2153 for ( s = 0, d = 0; s < val->bv_len; ) {
2154 if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2157 str[ d++ ] = val->bv_val[ s++ ];
2167 * Length of the (supposedly) AD canonical string representation,
2168 * accounting for escaped hex of UTF-8 chars
2171 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2180 if ( val->bv_len == 0 ) {
2184 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2186 * FIXME: Turn the value into a binary encoded BER?
2191 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2192 if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2207 * convert to (supposedly) AD string representation,
2208 * escaping with hex the UTF-8 stuff;
2209 * assume the destination has enough room for escaping
2212 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2220 if ( val->bv_len == 0 ) {
2225 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2227 * FIXME: Turn the value into a binary encoded BER?
2235 * we assume the string has enough room for the hex encoding
2239 for ( s = 0, d = 0; s < val->bv_len; ) {
2240 if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2243 str[ d++ ] = val->bv_val[ s++ ];
2253 * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2254 * the forst part of the AD representation of the DN is written in DNS
2255 * form, i.e. dot separated domain name components (as suggested
2256 * by Luke Howard, http://www.padl.com/~lukeh)
2259 dn2domain( LDAPDN *dn, char *str, int *iRDN )
2262 int domain = 0, first = 1;
2263 ber_len_t l = 1; /* we move the null also */
2265 /* we are guaranteed there's enough memory in str */
2271 assert( *iRDN > 0 );
2273 for ( i = *iRDN; i >= 0; i-- ) {
2277 assert( dn[ i ][ 0 ] );
2280 assert( rdn[ 0 ][ 0 ] );
2281 ava = rdn[ 0 ][ 0 ];
2283 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2291 AC_MEMCPY( str, ava->la_value->bv_val,
2292 ava->la_value->bv_len + 1);
2293 l += ava->la_value->bv_len;
2296 AC_MEMCPY( str + ava->la_value->bv_len + 1, str, l);
2297 AC_MEMCPY( str, ava->la_value->bv_val,
2298 ava->la_value->bv_len );
2299 str[ ava->la_value->bv_len ] = '.';
2300 l += ava->la_value->bv_len + 1;
2310 rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
2311 int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2318 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2319 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2321 /* len(type) + '=' + '+' | ',' */
2322 l += ava->la_attr->bv_len + 2;
2324 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2325 /* octothorpe + twice the length */
2326 l += 1 + 2 * ava->la_value->bv_len;
2330 unsigned f = flags | ava->la_flags;
2332 if ( ( *s2l )( ava->la_value, f, &vl ) ) {
2345 rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
2346 int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2351 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2352 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2354 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2355 ava->la_attr->bv_len );
2356 l += ava->la_attr->bv_len;
2360 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2362 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2365 l += 2 * ava->la_value->bv_len;
2369 unsigned f = flags | ava->la_flags;
2371 if ( ( *s2s )( ava->la_value, &str[ l ], f, &vl ) ) {
2376 str[ l++ ] = ( rdn[ iAVA + 1 ] ? '+' : ',' );
2385 rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2392 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2393 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2395 /* len(type) + '=' + ',' | '/' */
2396 l += ava->la_attr->bv_len + 2;
2398 switch ( ava->la_flags ) {
2399 case LDAP_AVA_BINARY:
2400 /* octothorpe + twice the length */
2401 l += 1 + 2 * ava->la_value->bv_len;
2404 case LDAP_AVA_STRING: {
2406 unsigned f = flags | ava->la_flags;
2408 if ( strval2DCEstrlen( ava->la_value, f, &vl ) ) {
2426 rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2431 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2432 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2437 str[ l++ ] = ( iAVA ? ',' : '/' );
2440 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2441 ava->la_attr->bv_len );
2442 l += ava->la_attr->bv_len;
2446 switch ( ava->la_flags ) {
2447 case LDAP_AVA_BINARY:
2449 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2452 l += 2 * ava->la_value->bv_len;
2455 case LDAP_AVA_STRING: {
2457 unsigned f = flags | ava->la_flags;
2459 if ( strval2DCEstr( ava->la_value, &str[ l ], f, &vl ) ) {
2477 rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2487 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2488 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2491 l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
2493 /* FIXME: are binary values allowed in UFN? */
2494 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2495 /* octothorpe + twice the value */
2496 l += 1 + 2 * ava->la_value->bv_len;
2500 unsigned f = flags | ava->la_flags;
2502 if ( strval2strlen( ava->la_value, f, &vl ) ) {
2515 rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
2520 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2521 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2523 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2525 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2528 l += 2 * ava->la_value->bv_len;
2532 unsigned f = flags | ava->la_flags;
2534 if ( strval2str( ava->la_value, &str[ l ], f, &vl ) ) {
2540 if ( rdn[ iAVA + 1 ]) {
2541 AC_MEMCPY( &str[ l ], " + ", 3 );
2545 AC_MEMCPY( &str[ l ], ", ", 2 );
2556 rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2566 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2567 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2572 /* FIXME: are binary values allowed in UFN? */
2573 switch ( ava->la_flags ) {
2574 case LDAP_AVA_BINARY:
2575 /* octothorpe + twice the value */
2576 l += 1 + 2 * ava->la_value->bv_len;
2579 case LDAP_AVA_STRING: {
2581 unsigned f = flags | ava->la_flags;
2583 if ( strval2ADstrlen( ava->la_value, f, &vl ) ) {
2601 rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2606 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2607 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2612 str[ l++ ] = ( iAVA ? ',' : '/' );
2615 switch ( ava->la_flags ) {
2616 case LDAP_AVA_BINARY:
2618 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2621 l += 2 * ava->la_value->bv_len;
2624 case LDAP_AVA_STRING: {
2626 unsigned f = flags | ava->la_flags;
2628 if ( strval2ADstr( ava->la_value, &str[ l ], f, &vl ) ) {
2648 * Returns in str a string representation of rdn based on flags.
2649 * There is some duplication of code between this and ldap_dn2str;
2650 * this is wanted to reduce the allocation of temporary buffers.
2653 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2660 if ( rdn == NULL ) {
2661 *str = LDAP_STRDUP( "" );
2662 return( LDAP_SUCCESS );
2666 * This routine wastes "back" bytes at the end of the string
2670 switch ( LDAP_DN_FORMAT( flags ) ) {
2671 case LDAP_DN_FORMAT_LDAPV3:
2672 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2673 return( LDAP_OTHER );
2677 case LDAP_DN_FORMAT_LDAPV2:
2678 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2679 return( LDAP_OTHER );
2683 case LDAP_DN_FORMAT_UFN:
2684 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2685 return( LDAP_OTHER );
2689 case LDAP_DN_FORMAT_DCE:
2690 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2691 return( LDAP_OTHER );
2695 case LDAP_DN_FORMAT_AD_CANONICAL:
2696 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2697 return( LDAP_OTHER );
2702 return( LDAP_INVALID_DN_SYNTAX );
2705 *str = LDAP_MALLOC( l + 1 );
2707 switch ( LDAP_DN_FORMAT( flags ) ) {
2708 case LDAP_DN_FORMAT_LDAPV3:
2709 rc = rdn2str( rdn, *str, flags, &l, strval2str );
2713 case LDAP_DN_FORMAT_LDAPV2:
2714 rc = rdn2str( rdn, *str, flags, &l, strval2IA5str );
2718 case LDAP_DN_FORMAT_UFN:
2719 rc = rdn2UFNstr( rdn, *str, flags, &l );
2723 case LDAP_DN_FORMAT_DCE:
2724 rc = rdn2DCEstr( rdn, *str, flags, &l, 1 );
2728 case LDAP_DN_FORMAT_AD_CANONICAL:
2729 rc = rdn2ADstr( rdn, *str, flags, &l, 1 );
2734 /* need at least one of the previous */
2735 return( LDAP_OTHER );
2739 ldap_memfree( *str );
2740 return( LDAP_OTHER );
2743 ( *str )[ l - back ] = '\0';
2745 return( LDAP_SUCCESS );
2749 * Very bulk implementation; many optimizations can be performed
2750 * - a NULL dn results in an empty string ""
2753 * a) what do we do if a UTF-8 string must be converted in LDAPv2?
2754 * we must encode it in binary form ('#' + HEXPAIRs)
2755 * b) does DCE/AD support UTF-8?
2756 * no clue; don't think so.
2757 * c) what do we do when binary values must be converted in UTF/DCE/AD?
2758 * use binary encoded BER
2760 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
2763 int rc = LDAP_OTHER;
2766 /* stringifying helpers for LDAPv3/LDAPv2 */
2767 int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2768 int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2772 Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2str(%u)\n%s%s", flags, "", "" );
2777 * a null dn means an empty dn string
2778 * FIXME: better raise an error?
2781 *str = LDAP_STRDUP( "" );
2782 return( LDAP_SUCCESS );
2785 switch ( LDAP_DN_FORMAT( flags ) ) {
2786 case LDAP_DN_FORMAT_LDAPV3:
2787 sv2l = strval2strlen;
2791 case LDAP_DN_FORMAT_LDAPV2:
2792 sv2l = strval2IA5strlen;
2793 sv2s = strval2IA5str;
2796 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2798 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2800 if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
2801 goto return_results;
2807 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2808 rc = LDAP_NO_MEMORY;
2812 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
2814 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2816 if ( rdn2str( rdn, &( *str )[ l ], flags,
2820 goto return_results;
2828 * trim the last ',' (the allocated memory
2829 * is one byte longer than required)
2831 ( *str )[ len - 1 ] = '\0';
2836 case LDAP_DN_FORMAT_UFN: {
2839 * FIXME: quoting from RFC 1781:
2841 To take a distinguished name, and generate a name of this format with
2842 attribute types omitted, the following steps are followed.
2844 1. If the first attribute is of type CommonName, the type may be
2847 2. If the last attribute is of type Country, the type may be
2850 3. If the last attribute is of type Country, the last
2851 Organisation attribute may have the type omitted.
2853 4. All attributes of type OrganisationalUnit may have the type
2854 omitted, unless they are after an Organisation attribute or
2855 the first attribute is of type OrganisationalUnit.
2857 * this should be the pedantic implementation.
2859 * Here the standard implementation reflects
2860 * the one historically provided by OpenLDAP
2861 * (and UMIch, I presume), with the variant
2862 * of spaces and plusses (' + ') separating
2865 * A non-standard but nice implementation could
2866 * be to turn the final "dc" attributes into a
2867 * dot-separated domain.
2869 * Other improvements could involve the use of
2870 * friendly country names and so.
2873 int leftmost_dc = -1;
2875 #endif /* DC_IN_UFN */
2877 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2879 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2881 if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
2882 goto return_results;
2887 if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
2888 if ( leftmost_dc == -1 ) {
2894 #endif /* DC_IN_UFN */
2897 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2898 rc = LDAP_NO_MEMORY;
2903 if ( leftmost_dc == -1 ) {
2904 #endif /* DC_IN_UFN */
2905 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
2907 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2909 if ( rdn2UFNstr( rdn, &( *str )[ l ],
2913 goto return_results;
2919 * trim the last ', ' (the allocated memory
2920 * is two bytes longer than required)
2922 ( *str )[ len - 2 ] = '\0';
2925 last_iRDN = iRDN - 1;
2927 for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
2929 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2931 if ( rdn2UFNstr( rdn, &( *str )[ l ],
2935 goto return_results;
2940 if ( !dn2domain( dn, &( *str )[ l ], &last_iRDN ) ) {
2943 goto return_results;
2946 /* the string is correctly terminated by dn2domain */
2948 #endif /* DC_IN_UFN */
2954 case LDAP_DN_FORMAT_DCE:
2956 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2958 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2960 if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
2961 goto return_results;
2967 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2968 rc = LDAP_NO_MEMORY;
2972 for ( l = 0; iRDN--; ) {
2974 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2976 if ( rdn2DCEstr( rdn, &( *str )[ l ], flags,
2980 goto return_results;
2987 ( *str )[ len ] = '\0';
2992 case LDAP_DN_FORMAT_AD_CANONICAL: {
2995 * Sort of UFN for DCE DNs: a slash ('/') separated
2996 * global->local DN with no types; strictly speaking,
2997 * the naming context should be a domain, which is
2998 * written in DNS-style, e.g. dot-deparated.
3002 * "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3006 * "microsoft.com/People/Bill,Gates"
3008 for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
3010 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3012 if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
3013 goto return_results;
3019 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3020 rc = LDAP_NO_MEMORY;
3025 if ( iRDN && dn2domain( dn, *str, &iRDN ) ) {
3026 for ( l = strlen( *str ); iRDN >= 0 ; iRDN-- ) {
3028 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3030 if ( rdn2ADstr( rdn, &( *str )[ l ],
3031 flags, &rdnl, 0 ) ) {
3034 goto return_results;
3043 * Strictly speaking, AD canonical requires
3044 * a DN to be in the form "..., dc=smtg",
3045 * i.e. terminated by a domain component
3047 if ( flags & LDAP_DN_PEDANTIC ) {
3050 rc = LDAP_INVALID_DN_SYNTAX;
3054 for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3056 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3058 if ( rdn2ADstr( rdn, &( *str )[ l ],
3059 flags, &rdnl, first ) ) {
3062 goto return_results;
3071 ( *str )[ len ] = '\0';
3078 return( LDAP_INVALID_DN_SYNTAX );
3082 Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2str(%s,%u)=%d\n", *str, flags, rc );