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 /* forces the use of new dn parsing routines */
27 /* #define USE_LDAP_DN_PARSING */
28 /* extension to UFN that turns trailing "dc=value" rdns in DNS style,
29 * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */
32 static char *dn2dn( const char *dnin, unsigned fin, unsigned fout );
34 /* from libraries/libldap/schema.c */
35 extern char * parse_numericoid(const char **sp, int *code, const int flags);
37 /* parsing/printing routines */
38 static int str2strval( const char *str, struct berval **val,
39 const char **next, unsigned flags, unsigned *retFlags );
40 static int DCE2strval( const char *str, struct berval **val,
41 const char **next, unsigned flags );
42 static int IA52strval( const char *str, struct berval **val,
43 const char **next, unsigned flags );
44 static int quotedIA52strval( const char *str, struct berval **val,
45 const char **next, unsigned flags );
46 static int hexstr2binval( const char *str, struct berval **val,
47 const char **next, unsigned flags );
48 static int hexstr2bin( const char *str, char *c );
49 static int byte2hexpair( const char *val, char *pair );
50 static int binval2hexstr( struct berval *val, char *str );
51 static int strval2strlen( struct berval *val, unsigned flags,
53 static int strval2str( struct berval *val, char *str, unsigned flags,
55 static int strval2IA5strlen( struct berval *val, unsigned flags,
57 static int strval2IA5str( struct berval *val, char *str, unsigned flags,
59 static int strval2DCEstrlen( struct berval *val, unsigned flags,
61 static int strval2DCEstr( struct berval *val, char *str, unsigned flags,
63 static int strval2ADstrlen( struct berval *val, unsigned flags,
65 static int strval2ADstr( struct berval *val, char *str, unsigned flags,
67 static int dn2domain( LDAPDN *dn, char *str, int *iRDN );
70 LDAPAVA * ldapava_new( const struct berval *attr, const struct berval *val,
72 void ldapava_free( LDAPAVA *ava );
73 LDAPRDN * ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava );
74 LDAPRDN * ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where );
75 /* void ldapava_free_rdn( LDAPRDN *rdn ); in ldap.h */
76 LDAPDN * ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn );
77 LDAPDN * ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where );
78 /* void ldapava_free_dn( LDAPDN *dn ); in ldap.h */
80 /* Higher level helpers */
81 static int rdn2strlen( LDAPRDN *rdn, ber_len_t *len,
82 int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
83 static int rdn2str( LDAPRDN *rdn, char *str, ber_len_t *len,
84 int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
85 static int rdn2UFNstrlen( LDAPRDN *rdn, ber_len_t *len );
86 static int rdn2UFNstr( LDAPRDN *rdn, char *str, ber_len_t *len );
87 static int rdn2DCEstrlen( LDAPRDN *rdn, ber_len_t *len );
88 static int rdn2DCEstr( LDAPRDN *rdn, char *str, ber_len_t *len, int first );
89 static int rdn2ADstrlen( LDAPRDN *rdn, ber_len_t *len );
90 static int rdn2ADstr( LDAPRDN *rdn, char *str, ber_len_t *len, int first );
92 #ifndef USE_LDAP_DN_PARSING /* deprecated */
93 #define NAME_TYPE_LDAP_RDN 0
94 #define NAME_TYPE_LDAP_DN 1
95 #define NAME_TYPE_DCE_DN 2
97 static char **explode_name( const char *name, int notypes, int is_type );
98 #endif /* !USE_LDAP_DN_PARSING */
101 * RFC 1823 ldap_get_dn
104 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
109 Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
111 if ( entry == NULL ) {
112 ld->ld_errno = LDAP_PARAM_ERROR;
116 tmp = *entry->lm_ber; /* struct copy */
117 if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
118 ld->ld_errno = LDAP_DECODING_ERROR;
126 * RFC 1823 ldap_dn2ufn
129 ldap_dn2ufn( LDAP_CONST char *dn )
131 #ifndef USE_LDAP_DN_PARSING /* deprecated */
136 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
138 /* produces completely untyped UFNs */
144 vals = ldap_explode_dn( dn , 0 );
149 for ( i = 0; vals[i]; i++ ) {
152 rvals = ldap_explode_rdn( vals[i] , 1 );
153 if ( rvals == NULL ) {
158 LDAP_FREE( vals[i] );
159 vals[i] = ldap_charray2str( rvals, " + " );
163 ufn = ldap_charray2str( vals, ", " );
167 #else /* USE_LDAP_DN_PARSING */
168 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
170 return dn2dn( dn, LDAP_DN_FORMAT_LDAPV3, LDAP_DN_FORMAT_UFN );
171 #endif /* USE_LDAP_DN_PARSING */
175 * RFC 1823 ldap_explode_dn
178 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
180 #ifndef USE_LDAP_DN_PARSING /* deprecated */
181 Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
183 return explode_name( dn, notypes, NAME_TYPE_LDAP_DN );
184 #else /* USE_LDAP_DN_PARSING */
186 char **values = NULL;
188 unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
190 Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
192 if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAPV3 )
197 for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) {
198 char *str, **v = NULL;
200 ldap_rdn2str( tmpDN[ iRDN ][ 0 ], &str, flag );
202 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iRDN ) );
204 LBER_VFREE( values );
205 ldapava_free_dn( tmpDN );
209 values[ iRDN ] = str;
211 values[ iRDN ] = NULL;
214 #endif /* USE_LDAP_DN_PARSING */
218 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
220 #ifndef USE_LDAP_DN_PARSING /* deprecated */
221 Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
223 return explode_name( rdn, notypes, NAME_TYPE_LDAP_RDN );
224 #else /* USE_LDAP_DN_PARSING */
226 char **values = NULL;
228 unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
230 Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
233 * we assume this dn is made of one rdn only
235 if ( ldap_str2dn( rdn, &tmpDN, LDAP_DN_FORMAT_LDAPV3 )
240 for ( iAVA = 0; tmpDN[ 0 ][ 0 ][ iAVA ]; iAVA++ ) {
241 ber_len_t l = 0, vl, al = 0;
242 char *str, **v = NULL;
243 LDAPAVA *ava = tmpDN[ 0 ][ 0 ][ iAVA ][ 0 ];
245 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iAVA ) );
251 if ( ava->la_flags == LDAP_AVA_BINARY ) {
252 vl = 1 + 2 * ava->la_value->bv_len;
255 if ( strval2strlen( ava->la_value,
256 ava->la_flags, &vl ) ) {
262 al = ava->la_attr->bv_len;
263 l = vl + ava->la_attr->bv_len + 1;
265 str = LDAP_MALLOC( l + 1 );
266 AC_MEMCPY( str, ava->la_attr->bv_val,
267 ava->la_attr->bv_len );
272 str = LDAP_MALLOC( l + 1 );
275 if ( ava->la_flags == LDAP_AVA_BINARY ) {
277 if ( binval2hexstr( ava->la_value, &str[ al ] ) ) {
282 if ( strval2str( ava->la_value, &str[ al ],
283 ava->la_flags, &vl ) ) {
289 values[ iAVA ] = str;
291 values[ iAVA ] = NULL;
293 ldapava_free_dn( tmpDN );
298 LBER_VFREE( values );
299 ldapava_free_dn( tmpDN );
301 #endif /* USE_LDAP_DN_PARSING */
305 ldap_dn2dcedn( LDAP_CONST char *dn )
307 #ifndef USE_LDAP_DN_PARSING /* deprecated */
308 char *dce, *q, **rdns, **p;
311 Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
313 rdns = explode_name( dn, 0, NAME_TYPE_LDAP_DN );
314 if ( rdns == NULL ) {
318 for ( p = rdns; *p != NULL; p++ ) {
319 len += strlen( *p ) + 1;
322 q = dce = LDAP_MALLOC( len + 1 );
327 p--; /* get back past NULL */
329 for ( ; p != rdns; p-- ) {
341 #else /* USE_LDAP_DN_PARSING */
342 Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
344 return dn2dn( dn, LDAP_DN_FORMAT_LDAPV3, LDAP_DN_FORMAT_DCE );
345 #endif /* USE_LDAP_DN_PARSING */
349 ldap_dcedn2dn( LDAP_CONST char *dce )
351 #ifndef USE_LDAP_DN_PARSING
352 char *dn, *q, **rdns, **p;
355 Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
357 rdns = explode_name( dce, 0, NAME_TYPE_DCE_DN );
358 if ( rdns == NULL ) {
364 for ( p = rdns; *p != NULL; p++ ) {
365 len += strlen( *p ) + 1;
368 q = dn = LDAP_MALLOC( len );
375 for ( ; p != rdns; p-- ) {
383 /* the name was fully qualified, thus the most-significant
384 * RDN was empty. trash the last comma */
388 /* the name was relative. copy the most significant RDN */
393 #else /* USE_LDAP_DN_PARSING */
394 Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
396 return dn2dn( dce, LDAP_DN_FORMAT_DCE, LDAP_DN_FORMAT_LDAPV3 );
397 #endif /* USE_LDAP_DN_PARSING */
401 ldap_dn2ad_canonical( LDAP_CONST char *dn )
403 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
405 return dn2dn( dn, LDAP_DN_FORMAT_LDAPV3, LDAP_DN_FORMAT_AD_CANONICAL );
408 #ifndef USE_LDAP_DN_PARSING /* deprecated */
413 explode_name( const char *name, int notypes, int is_type )
415 const char *p, *q, *rdn;
417 int offset, state, have_equals, count = 0, endquote, len;
420 if(name == NULL) name = "";
422 /* skip leading whitespace */
423 while( ldap_utf8_isspace( name )) {
424 LDAP_UTF8_INCR( name );
439 if ( p[1] != '\0' ) {
440 offset = LDAP_UTF8_OFFSET(++p);
444 if ( state == INQUOTE )
450 if( state == OUTQUOTE ) have_equals++;
453 if (is_type == NAME_TYPE_LDAP_RDN)
457 if (is_type == NAME_TYPE_DCE_DN)
462 if (is_type == NAME_TYPE_LDAP_DN)
467 if ( state == OUTQUOTE ) {
471 if ( parts == NULL ) {
472 if (( parts = (char **)LDAP_MALLOC( 8
473 * sizeof( char *))) == NULL )
475 } else if ( count >= 8 ) {
476 if (( parts = (char **)LDAP_REALLOC( parts,
477 (count+1) * sizeof( char *)))
482 parts[ count ] = NULL;
486 for ( q = rdn; q < p && *q != '='; ++q ) {
498 if ( p[-1] == '"' ) {
506 if (( parts[ count-1 ] = (char *)LDAP_CALLOC( 1,
509 AC_MEMCPY( parts[ count-1 ], rdn, len );
512 /* skip trailing spaces */
513 while( len > 0 && ldap_utf8_isspace(
514 &parts[count-1][len-1] ) )
520 parts[ count-1 ][ len ] = '\0';
524 * Don't forget to increment 'p' back to where
525 * it should be. If we don't, then we will
526 * never get past an "end quote."
531 rdn = *p ? &p[1] : p;
532 while ( ldap_utf8_isspace( rdn ) )
540 #endif /* !USE_LDAP_DN_PARSING */
543 * helper that changes the string representation of dnin
544 * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
547 * LDAP_DN_FORMAT_LDAPV3 (rfc 2253 and ldapbis)
548 * LDAP_DN_FORMAT_LDAPV2 (rfc 1779)
549 * LDAP_DN_FORMAT_DCE (?)
551 * fout can be any of the above plus:
552 * LDAP_DN_FORMAT_UFN (rfc 1781, partial and with extensions)
553 * LDAP_DN_FORMAT_AD_CANONICAL (?)
556 dn2dn( const char *dnin, unsigned fin, unsigned fout )
559 LDAPDN *tmpDN = NULL;
565 if ( ldap_str2dn( dnin , &tmpDN, fin ) != LDAP_SUCCESS ) {
569 /* don't care about the result ... */
570 ldap_dn2str( tmpDN, &dnout, fout );
572 ldapava_free_dn( tmpDN );
580 /* #define B4ATTRTYPE 0x0001 */
581 #define B4OIDATTRTYPE 0x0002
582 #define B4STRINGATTRTYPE 0x0003
584 #define B4AVAEQUALS 0x0100
585 #define B4AVASEP 0x0200
586 #define B4RDNSEP 0x0300
587 #define GOTAVA 0x0400
589 #define B4ATTRVALUE 0x0010
590 #define B4STRINGVALUE 0x0020
591 #define B4IA5VALUEQUOTED 0x0030
592 #define B4IA5VALUE 0x0040
593 #define B4BINARYVALUE 0x0050
595 /* Helpers (mostly from slapd.h; maybe it should be rewritten from this) */
596 #define LDAP_DN_ASCII_SPACE(c) \
597 ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
598 #define LDAP_DN_ASCII_LOWER(c) ( (c) >= 'a' && (c) <= 'z' )
599 #define LDAP_DN_ASCII_UPPER(c) ( (c) >= 'A' && (c) <= 'Z' )
600 #define LDAP_DN_ASCII_ALPHA(c) \
601 ( LDAP_DN_ASCII_LOWER(c) || LDAP_DN_ASCII_UPPER(c) )
602 #define LDAP_DN_ASCII_DIGIT(c) ( (c) >= '0' && (c) <= '9' )
603 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) ( (c) >= 'a' && (c) <= 'f' )
604 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) ( (c) >= 'A' && (c) <= 'F' )
605 #define LDAP_DN_ASCII_HEXDIGIT(c) \
606 ( LDAP_DN_ASCII_DIGIT(c) \
607 || LDAP_DN_ASCII_LCASE_HEXALPHA(c) \
608 || LDAP_DN_ASCII_UCASE_HEXALPHA(c) )
609 #define LDAP_DN_ASCII_ALNUM(c) \
610 ( LDAP_DN_ASCII_ALPHA(c) || LDAP_DN_ASCII_DIGIT(c) )
611 #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' )
614 #define LDAP_DN_OID_LEADCHAR(c) ( LDAP_DN_ASCII_DIGIT(c) )
615 #define LDAP_DN_DESC_LEADCHAR(c) ( LDAP_DN_ASCII_ALPHA(c) )
616 #define LDAP_DN_DESC_CHAR(c) ( LDAP_DN_ASCII_ALNUM(c) || (c) == '-' )
617 #define LDAP_DN_LANG_SEP(c) ( (c) == ';' )
618 #define LDAP_DN_ATTRDESC_CHAR(c) \
619 ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
621 /* special symbols */
622 #define LDAP_DN_AVA_EQUALS(c) ( (c) == '=' )
623 #define LDAP_DN_AVA_SEP(c) ( (c) == '+' )
624 #define LDAP_DN_RDN_SEP(c) ( (c) == ',' )
625 #define LDAP_DN_RDN_SEP_V2(c) ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
626 #define LDAP_DN_OCTOTHORPE(c) ( (c) == '#' )
627 #define LDAP_DN_QUOTES(c) ( (c) == '\"' )
628 #define LDAP_DN_ESCAPE(c) ( (c) == '\\' )
629 #define LDAP_DN_VALUE_END(c) \
630 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
631 #define LDAP_DN_NE(c) \
632 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
633 || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
634 #define LDAP_DN_NEEDESCAPE(c) \
635 ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
636 #define LDAP_DN_NEEDESCAPE_LEAD(c) \
637 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) )
638 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
639 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
640 #define LDAP_DN_WILLESCAPE(c) \
641 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
644 #define LDAP_DN_VALUE_END_V2(c) \
645 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
647 #define LDAP_DN_V2_SPECIAL(c) \
648 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
649 || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
650 || LDAP_DN_OCTOTHORPE(c) )
651 #define LDAP_DN_V2_PAIR(c) \
652 ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
655 * DCE (mostly from Luke Howard and IBM implementation for AIX)
657 * From: "Application Development Guide - Directory Services" (FIXME: add link?)
658 * Here escapes and valid chars for GDS are considered; as soon as more
659 * specific info is found, the macros will be updated.
661 * Chars: 'a'-'z', 'A'-'Z', '0'-'9',
662 * '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
664 * Metachars: '/', ',', '=', '\'.
666 * the '\' is used to escape other metachars.
672 * Attribute types must start with alphabetic chars and can contain
673 * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
675 #define LDAP_DN_RDN_SEP_DCE(c) ( (c) == '/' )
676 #define LDAP_DN_AVA_SEP_DCE(c) ( (c) == ',' )
677 #define LDAP_DN_ESCAPE_DCE(c) ( LDAP_DN_ESCAPE(c) )
678 #define LDAP_DN_VALUE_END_DCE(c) \
679 ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
680 #define LDAP_DN_NEEDESCAPE_DCE(c) \
681 ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
684 #define LDAP_DN_RDN_SEP_AD(c) ( (c) == '/' )
685 #define LDAP_DN_ESCAPE_AD(c) ( LDAP_DN_ESCAPE(c) )
686 #define LDAP_DN_AVA_SEP_AD(c) ( (c) == ',' ) /* assume same as DCE */
687 #define LDAP_DN_VALUE_END_AD(c) \
688 ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
689 #define LDAP_DN_NEEDESCAPE_AD(c) \
690 ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
693 #define LDAP_DN_HEXPAIR(s) \
694 ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
695 #define LDAP_DC_ATTR "dc"
696 /* better look at the AttributeDescription? */
698 /* FIXME: no composite rdn or non-"dc" types, right?
699 * (what about "dc" in OID form?) */
700 /* FIXME: we do not allow binary values in domain, right? */
701 /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
702 #define LDAP_DN_IS_RDN_DC( rdn ) \
703 ( ( rdn ) && ( rdn )[ 0 ][ 0 ] && !( rdn )[ 1 ] \
704 && ( ( rdn )[ 0 ][ 0 ]->la_flags == LDAP_AVA_STRING ) \
705 && ! strcasecmp( ( rdn )[ 0 ][ 0 ]->la_attr->bv_val, LDAP_DC_ATTR ) )
707 /* Composite rules */
708 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
709 ( ( (f) & LDAP_DN_FORMAT_LDAPV2 ) \
710 || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
711 #define LDAP_DN_ALLOW_SPACES(f) \
712 ( ( (f) & LDAP_DN_FORMAT_LDAPV2 ) \
713 || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
714 #define LDAP_DN_LDAPV3(f) \
715 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
716 #define LDAP_DN_LDAPV2(f) \
717 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
718 #define LDAP_DN_DCE(f) \
719 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
720 #define LDAP_DN_UFN(f) \
721 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
722 #define LDAP_DN_ADC(f) \
723 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
724 #define LDAP_DN_FORMAT(f) ( (f) & LDAP_DN_FORMAT_MASK )
727 * LDAPAVA helpers (will become part of the API for operations
728 * on structural representations of DNs).
731 ldapava_new( const struct berval *attr, const struct berval *val,
739 ava = LDAP_MALLOC( sizeof( LDAPAVA ) );
741 /* should we test it? */
746 ava->la_attr = ( struct berval * )attr;
747 ava->la_value = ( struct berval * )val;
748 ava->la_flags = flags;
754 ldapava_free( LDAPAVA *ava )
758 ber_bvfree( ava->la_attr );
759 ber_bvfree( ava->la_value );
765 ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava )
773 for ( i = 0U; rdn[ i ]; i++ ) {
777 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
778 newRDN[ i ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
779 newRDN[ i ][ 0 ] = ava;
780 newRDN[ i + 1 ] = NULL;
786 ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where )
794 for ( i = 0U; rdn[ i ]; i++ ) {
800 /* assume "at end", which corresponds to
801 * ldapava_append_to_rdn */
804 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
806 /* data after insert point */
807 AC_MEMCPY( &newRDN[ where + 1 ], &newRDN[ where ],
808 ( i - where ) * sizeof( LDAPRDN * ) );
810 newRDN[ where ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
811 newRDN[ where ][ 0 ] = ava;
812 newRDN[ i + 1 ] = NULL;
818 ldapava_free_rdn( LDAPRDN *rdn )
826 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
827 assert( rdn[ iAVA ][ 0 ] );
829 ldapava_free( rdn[ iAVA ][ 0 ] );
836 ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn )
844 for ( i = 0U; dn[ i ]; i++ ) {
848 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
849 newDN[ i ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
850 newDN[ i ][ 0 ] = rdn;
851 newDN[ i + 1 ] = NULL;
857 ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where )
865 for ( i = 0U; dn[ i ]; i++ ) {
871 /* assume "at end", which corresponds to
872 * ldapava_append_to_dn */
875 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
877 /* data after insert point */
878 AC_MEMCPY( &newDN[ where + 1 ], &newDN[ where ],
879 ( i - where ) * sizeof( LDAPDN * ) );
881 newDN[ where ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
882 newDN[ where ][ 0 ] = rdn;
883 newDN[ i + 1 ] = NULL;
889 ldapava_free_dn( LDAPDN *dn )
897 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
898 assert( dn[ iRDN ][ 0 ] );
900 ldapava_free_rdn( dn[ iRDN ][ 0 ] );
907 * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
908 * into a structured representation of the DN, by separating attribute
909 * types and values encoded in the more appropriate form, which is
910 * string or OID for attribute types and binary form of the BER encoded
911 * value or Unicode string. Formats different from LDAPv3 are parsed
912 * according to their own rules and turned into the more appropriate
913 * form according to LDAPv3.
915 * NOTE: I realize the code is getting spaghettish; it is rather
916 * experimental and will hopefully turn into something more simple
917 * and readable as soon as it works as expected.
921 ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
924 int rc = LDAP_INVALID_DN_SYNTAX;
926 LDAPDN *newDN = NULL;
927 LDAPRDN *newRDN = NULL;
932 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );
936 switch ( LDAP_DN_FORMAT( flags ) ) {
937 case LDAP_DN_FORMAT_LDAPV3:
938 case LDAP_DN_FORMAT_LDAPV2:
939 case LDAP_DN_FORMAT_DCE:
942 /* unsupported in str2dn */
943 case LDAP_DN_FORMAT_UFN:
944 case LDAP_DN_FORMAT_AD_CANONICAL:
945 return( LDAP_INVALID_DN_SYNTAX );
948 return( LDAP_OTHER );
951 if ( str[ 0 ] == '\0' ) {
952 return( LDAP_SUCCESS );
956 if ( LDAP_DN_DCE( flags ) ) {
959 * (from Luke Howard: thnx) A RDN separator is required
960 * at the beginning of an (absolute) DN.
962 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
968 for ( ; p[ 0 ]; p++ ) {
971 rc = ldap_str2rdn( p, &newRDN, &p, flags );
972 if ( rc != LDAP_SUCCESS ) {
977 * We expect a rdn separator
980 switch ( LDAP_DN_FORMAT( flags ) ) {
981 case LDAP_DN_FORMAT_LDAPV3:
982 if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
988 case LDAP_DN_FORMAT_LDAPV2:
989 if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
995 case LDAP_DN_FORMAT_DCE:
996 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
1005 if ( LDAP_DN_DCE( flags ) ) {
1006 /* add in reversed order */
1007 dn = ldapava_insert_into_dn( newDN, newRDN, 0 );
1009 dn = ldapava_append_to_dn( newDN, newRDN );
1013 rc = LDAP_NO_MEMORY;
1020 if ( p[ 0 ] == '\0' ) {
1023 * the DN is over, phew
1032 ldapava_free_rdn( newRDN );
1036 ldapava_free_dn( newDN );
1042 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
1051 * Parses a relative DN according to flags up to a rdn separator
1052 * or to the end of str.
1053 * Returns the rdn and a pointer to the string continuation, which
1054 * corresponds to the rdn separator or to '\0' in case the string is over.
1057 ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
1061 int rc = LDAP_INVALID_DN_SYNTAX;
1062 int attrTypeEncoding = LDAP_AVA_STRING,
1063 attrValueEncoding = LDAP_AVA_STRING;
1065 struct berval *attrType = NULL;
1066 struct berval *attrValue = NULL;
1068 LDAPRDN *newRDN = NULL;
1074 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );
1079 switch ( LDAP_DN_FORMAT( flags ) ) {
1080 case LDAP_DN_FORMAT_LDAPV3:
1081 case LDAP_DN_FORMAT_LDAPV2:
1082 case LDAP_DN_FORMAT_DCE:
1085 /* unsupported in str2dn */
1086 case LDAP_DN_FORMAT_UFN:
1087 case LDAP_DN_FORMAT_AD_CANONICAL:
1088 return( LDAP_INVALID_DN_SYNTAX );
1091 return( LDAP_OTHER );
1094 if ( str[ 0 ] == '\0' ) {
1095 return( LDAP_SUCCESS );
1099 for ( ; p[ 0 ] || state == GOTAVA; ) {
1102 * The parser in principle advances one token a time,
1103 * or toggles state if preferable.
1108 * an AttributeType can be encoded as:
1109 * - its string representation; in detail, implementations
1110 * MUST recognize AttributeType string type names listed
1111 * in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
1112 * MAY recognize other names.
1113 * - its numeric OID (a dotted decimal string); in detail
1114 * RFC 2253 asserts that ``Implementations MUST allow
1115 * an oid in the attribute type to be prefixed by one
1116 * of the character strings "oid." or "OID."''. As soon
1117 * as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253
1118 * I'm not sure whether this is required or not any
1119 * longer; to be liberal, we still implement it.
1122 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1123 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
1130 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1131 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1136 /* whitespace is allowed (and trimmed) */
1138 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1143 /* error: we expected an AVA */
1149 if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
1150 state = B4OIDATTRTYPE;
1154 /* else must be alpha */
1155 if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
1159 /* LDAPv2 "oid." prefix */
1160 if ( LDAP_DN_LDAPV2( flags ) ) {
1162 * to be overly pedantic, we only accept
1165 if ( flags & LDAP_DN_PEDANTIC ) {
1166 if ( !strncmp( p, "OID.", 4 )
1167 || !strncmp( p, "oid.", 4 ) ) {
1169 state = B4OIDATTRTYPE;
1173 if ( !strncasecmp( p, "oid.", 4 ) ) {
1175 state = B4OIDATTRTYPE;
1181 state = B4STRINGATTRTYPE;
1184 case B4OIDATTRTYPE: {
1185 int err = LDAP_SUCCESS;
1188 type = parse_numericoid( &p, &err, 0 );
1189 if ( type == NULL ) {
1192 attrType = LDAP_MALLOC( sizeof( struct berval ) );
1193 if ( attrType== NULL ) {
1194 rc = LDAP_NO_MEMORY;
1197 attrType->bv_val = type;
1198 attrType->bv_len = strlen( type );
1199 attrTypeEncoding = LDAP_AVA_BINARY;
1201 state = B4AVAEQUALS;
1205 case B4STRINGATTRTYPE: {
1206 const char *startPos, *endPos = NULL;
1210 * the starting char has been found to be
1211 * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
1212 * FIXME: DCE attr types seem to have a more
1213 * restrictive syntax (no '-' ...)
1215 for ( startPos = p++; p[ 0 ]; p++ ) {
1216 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
1220 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
1223 * RFC 2253 does not explicitly
1224 * allow lang extensions to attribute
1227 if ( flags & LDAP_DN_PEDANTIC ) {
1232 * we trim ';' and following lang
1233 * and so from attribute types
1236 for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
1237 || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
1245 len = ( endPos ? endPos : p ) - startPos;
1250 assert( attrType == NULL );
1251 attrType = LDAP_MALLOC( sizeof( struct berval ) );
1252 if ( attrType == NULL ) {
1253 rc = LDAP_NO_MEMORY;
1256 attrType->bv_val = LDAP_STRNDUP( startPos, len );
1257 if ( attrType->bv_val == NULL ) {
1258 rc = LDAP_NO_MEMORY;
1261 attrType->bv_len = len;
1262 attrTypeEncoding = LDAP_AVA_STRING;
1265 * here we need to decide whether to use it as is
1266 * or turn it in OID form; as a consequence, we
1267 * need to decide whether to binary encode the value
1270 state = B4AVAEQUALS;
1275 /* spaces may not be allowed */
1276 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1277 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1282 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1287 /* need equal sign */
1288 if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1293 /* spaces may not be allowed */
1294 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1295 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1300 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1306 * octothorpe means a BER encoded value will follow
1307 * FIXME: I don't think DCE will allow it
1309 if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1311 attrValueEncoding = LDAP_AVA_BINARY;
1312 state = B4BINARYVALUE;
1316 /* STRING value expected */
1319 * if we're pedantic, an attribute type in OID form
1320 * SHOULD imply a BER encoded attribute value; we
1321 * should at least issue a warning
1323 if ( ( flags & LDAP_DN_PEDANTIC )
1324 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1325 /* OID attrType SHOULD use binary encoding */
1329 attrValueEncoding = LDAP_AVA_STRING;
1332 * LDAPv2 allows the attribute value to be quoted;
1333 * also, IA5 values are expected, in principle
1335 if ( LDAP_DN_LDAPV2( flags ) ) {
1336 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1338 state = B4IA5VALUEQUOTED;
1347 * here STRING means RFC 2253 string
1348 * FIXME: what about DCE strings?
1350 state = B4STRINGVALUE;
1354 if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
1362 switch ( LDAP_DN_FORMAT( flags ) ) {
1363 case LDAP_DN_FORMAT_LDAPV3:
1364 if ( str2strval( p, &attrValue, &p, flags,
1365 &attrValueEncoding ) ) {
1370 case LDAP_DN_FORMAT_DCE:
1371 if ( DCE2strval( p, &attrValue, &p, flags ) ) {
1384 if ( IA52strval( p, &attrValue, &p, flags ) ) {
1391 case B4IA5VALUEQUOTED:
1393 /* lead quote already stripped */
1394 if ( quotedIA52strval( p, &attrValue,
1408 * we accept empty values
1410 ava = ldapava_new( attrType, attrValue,
1411 attrValueEncoding );
1412 if ( ava == NULL ) {
1413 rc = LDAP_NO_MEMORY;
1417 rdn = ldapava_append_to_rdn( newRDN, ava );
1418 if ( rdn == NULL ) {
1419 rc = LDAP_NO_MEMORY;
1425 * if we got an AVA separator ('+', or ',' for DCE )
1426 * we expect a new AVA for this RDN; otherwise
1427 * we add the RDN to the DN
1429 switch ( LDAP_DN_FORMAT( flags ) ) {
1430 case LDAP_DN_FORMAT_LDAPV3:
1431 case LDAP_DN_FORMAT_LDAPV2:
1432 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1437 case LDAP_DN_FORMAT_DCE:
1438 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1446 * the RDN is over, phew
1453 /* they should have been used in an AVA */
1469 /* They are set to NULL after they're used in an AVA */
1471 ber_bvfree( attrType );
1475 ber_bvfree( attrValue );
1479 ldapava_free_rdn( newRDN );
1484 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n",
1492 * reads in a UTF-8 string value, unescaping stuff:
1493 * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1494 * '\' + HEXPAIR(p) -> unhex(p)
1497 str2strval( const char *str, struct berval **val, const char **next, unsigned flags, unsigned *retFlags )
1499 const char *p, *startPos, *endPos = NULL;
1500 ber_len_t len, escapes, unescapes;
1509 for ( startPos = p = str, escapes = 0, unescapes = 0; p[ 0 ]; p++ ) {
1510 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1512 if ( p[ 0 ] == '\0' ) {
1515 if ( ( p == startPos + 1 && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1516 || ( LDAP_DN_VALUE_END( p[ 1 ] ) && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
1517 || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1522 if ( LDAP_DN_HEXPAIR( p ) ) {
1525 hexstr2bin( p, &c );
1528 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1531 * we assume the string is UTF-8
1533 *retFlags = LDAP_AVA_NONPRINTABLE;
1540 if ( LDAP_DN_PEDANTIC & flags ) {
1544 * FIXME: we allow escaping
1545 * of chars that don't need
1546 * to and do not belong to
1547 * HEXDIGITS (we also allow
1548 * single hexdigit; maybe we
1553 } else if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1556 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1558 * FIXME: maybe we can add
1559 * escapes if not pedantic?
1566 * we do allow unescaped spaces at the end
1567 * of the value only in non-pedantic mode
1569 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1570 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1571 if ( flags & LDAP_DN_PEDANTIC ) {
1575 /* strip trailing (unescaped) spaces */
1576 for ( endPos = p - 1;
1577 endPos > startPos + 1 &&
1578 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1579 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1586 * FIXME: test memory?
1588 len = ( endPos ? endPos : p ) - startPos - escapes - unescapes;
1589 *val = LDAP_MALLOC( sizeof( struct berval ) );
1590 ( *val )->bv_len = len;
1592 if ( escapes == 0 && unescapes == 0 ) {
1593 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1598 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1599 for ( s = 0, d = 0; d < len; ) {
1600 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1602 if ( ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( startPos[ s ] ) )
1603 || ( s == len - 1 && LDAP_DN_NEEDESCAPE_TRAIL( startPos[ s ] ) )
1604 || LDAP_DN_NEEDESCAPE( startPos[ s ] ) ) {
1605 ( *val )->bv_val[ d++ ] =
1608 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1611 hexstr2bin( &startPos[ s ], &c );
1612 ( *val )->bv_val[ d++ ] = c;
1617 * we allow escaping of chars
1618 * that do not need to
1620 ( *val )->bv_val[ d++ ] =
1625 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1629 ( *val )->bv_val[ d ] = '\0';
1630 assert( strlen( ( *val )->bv_val ) == len );
1640 DCE2strval( const char *str, struct berval **val, const char **next, unsigned flags )
1642 const char *p, *startPos, *endPos = NULL;
1643 ber_len_t len, escapes;
1652 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1653 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1655 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1662 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1667 * FIXME: can we accept anything else? I guess we need
1668 * to stop if a value is not legal
1673 * (unescaped) trailing spaces are trimmed must be silently ignored;
1676 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1677 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1678 if ( flags & LDAP_DN_PEDANTIC ) {
1682 /* strip trailing (unescaped) spaces */
1683 for ( endPos = p - 1;
1684 endPos > startPos + 1 &&
1685 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1686 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1693 len = ( endPos ? endPos : p ) - startPos - escapes;
1694 *val = LDAP_MALLOC( sizeof( struct berval ) );
1695 ( *val )->bv_len = len;
1696 if ( escapes == 0 ){
1697 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1702 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1703 for ( s = 0, d = 0; d < len; ) {
1705 * This point is reached only if escapes
1706 * are properly used, so all we need to
1709 if ( LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1713 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1715 ( *val )->bv_val[ d ] = '\0';
1716 assert( strlen( ( *val )->bv_val ) == len );
1725 IA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1727 const char *p, *startPos, *endPos = NULL;
1728 ber_len_t len, escapes;
1741 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1742 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1744 if ( p[ 0 ] == '\0' ) {
1748 if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1749 && ( LDAP_DN_PEDANTIC & flags ) ) {
1754 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1759 * FIXME: can we accept anything else? I guess we need
1760 * to stop if a value is not legal
1764 /* strip trailing (unescaped) spaces */
1766 endPos > startPos + 1 &&
1767 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1768 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1773 *val = LDAP_MALLOC( sizeof( struct berval ) );
1774 len = ( endPos ? endPos : p ) - startPos - escapes;
1775 ( *val )->bv_len = len;
1776 if ( escapes == 0 ) {
1777 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1782 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1783 for ( s = 0, d = 0; d < len; ) {
1784 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1787 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1789 ( *val )->bv_val[ d ] = '\0';
1790 assert( strlen( ( *val )->bv_val ) == len );
1798 quotedIA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1800 const char *p, *startPos, *endPos = NULL;
1802 unsigned escapes = 0;
1811 /* initial quote already eaten */
1812 for ( startPos = p = str; p[ 0 ]; p++ ) {
1814 * According to RFC 1779, the quoted value can
1815 * contain escaped as well as unescaped special values;
1816 * as a consequence we tolerate escaped values
1817 * (e.g. '"\,"' -> '\,') and escape unescaped specials
1818 * (e.g. '","' -> '\,').
1820 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1821 if ( p[ 1 ] == '\0' ) {
1826 if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1827 && ( LDAP_DN_PEDANTIC & flags ) ) {
1829 * do we allow to escape normal chars?
1830 * LDAPv2 does not allow any mechanism
1831 * for escaping chars with '\' and hex
1838 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1840 /* eat closing quotes */
1846 * FIXME: can we accept anything else? I guess we need
1847 * to stop if a value is not legal
1851 if ( endPos == NULL ) {
1855 /* Strip trailing (unescaped) spaces */
1856 for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1860 len = endPos - startPos - escapes;
1862 *val = LDAP_MALLOC( sizeof( struct berval ) );
1863 ( *val )->bv_len = len;
1864 if ( escapes == 0 ) {
1865 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1870 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1871 ( *val )->bv_len = len;
1873 for ( s = d = 0; d < len; ) {
1874 if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1877 ( *val )->bv_val[ d++ ] = str[ s++ ];
1879 ( *val )->bv_val[ d ] = '\0';
1880 assert( strlen( ( *val )->bv_val ) == len );
1889 hexstr2bin( const char *str, char *c )
1899 if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1905 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) ) {
1912 if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1918 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) ) {
1919 *c += c2 - 'a' + 10;
1927 hexstr2binval( const char *str, struct berval **val, const char **next, unsigned flags )
1929 const char *p, *startPos, *endPos = NULL;
1940 for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1941 switch ( LDAP_DN_FORMAT( flags ) ) {
1942 case LDAP_DN_FORMAT_LDAPV3:
1943 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1948 case LDAP_DN_FORMAT_LDAPV2:
1949 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1954 case LDAP_DN_FORMAT_DCE:
1955 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1961 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1962 if ( flags & LDAP_DN_PEDANTIC ) {
1967 for ( ; p[ 0 ]; p++ ) {
1968 switch ( LDAP_DN_FORMAT( flags ) ) {
1969 case LDAP_DN_FORMAT_LDAPV3:
1970 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1975 case LDAP_DN_FORMAT_LDAPV2:
1976 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1981 case LDAP_DN_FORMAT_DCE:
1982 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1991 if ( !LDAP_DN_HEXPAIR( p ) ) {
1998 len = ( ( endPos ? endPos : p ) - startPos ) / 2;
2000 assert( 2 * len == ( endPos ? endPos : p ) - startPos );
2002 *val = LDAP_MALLOC( sizeof( struct berval ) );
2003 if ( *val == NULL ) {
2004 return( LDAP_NO_MEMORY );
2007 ( *val )->bv_len = len;
2008 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
2009 if ( ( *val )->bv_val == NULL ) {
2011 return( LDAP_NO_MEMORY );
2014 for ( s = 0, d = 0; d < len; s += 2, d++ ) {
2017 hexstr2bin( &startPos[ s ], &c );
2019 ( *val )->bv_val[ d ] = c;
2022 ( *val )->bv_val[ d ] = '\0';
2029 * convert a byte in a hexadecimal pair
2032 byte2hexpair( const char *val, char *pair )
2034 static const char hexdig[] = "0123456789abcdef";
2040 * we assume the string has enough room for the hex encoding
2044 pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
2045 pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
2051 * convert a binary value in hexadecimal pairs
2054 binval2hexstr( struct berval *val, char *str )
2061 if ( val->bv_len == 0 ) {
2066 * we assume the string has enough room for the hex encoding
2070 for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
2071 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2078 * Length of the string representation, accounting for escaped hex
2082 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
2084 ber_len_t l, cl = 1;
2091 if ( val->bv_len == 0 ) {
2095 for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
2096 cl = ldap_utf8_charlen( p );
2098 /* illegal utf-8 char! */
2101 } else if ( cl > 1 ) {
2104 for ( cnt = 1; cnt < cl; cnt++ ) {
2105 if ( ( p[ cnt ] & 0x80 ) == 0x00 ) {
2109 /* need to escape it */
2113 * there might be some chars we want to escape in form
2114 * of a couple of hexdigits for optimization purposes
2116 } else if ( LDAP_DN_WILLESCAPE( p[ 0 ] ) ) {
2119 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2120 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2121 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2135 * convert to string representation, escaping with hex the UTF-8 stuff;
2136 * assume the destination has enough room for escaping
2139 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2141 ber_len_t s, d, end;
2147 if ( val->bv_len == 0 ) {
2153 * we assume the string has enough room for the hex encoding
2156 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2157 ber_len_t cl = ldap_utf8_charlen( &val->bv_val[ s ] );
2160 * there might be some chars we want to escape in form
2161 * of a couple of hexdigits for optimization purposes
2163 if ( cl > 1 || LDAP_DN_WILLESCAPE( val->bv_val[ s ] ) ) {
2166 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2172 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2173 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2174 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2177 str[ d++ ] = val->bv_val[ s++ ];
2187 * Length of the IA5 string representation (no UTF-8 allowed)
2190 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
2199 if ( val->bv_len == 0 ) {
2203 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2205 * Turn value into a binary encoded BER
2210 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2211 if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2212 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2213 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2228 * convert to string representation (np UTF-8)
2229 * assume the destination has enough room for escaping
2232 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2234 ber_len_t s, d, end;
2240 if ( val->bv_len == 0 ) {
2245 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2247 * Turn value into a binary encoded BER
2254 * we assume the string has enough room for the hex encoding
2258 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2259 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2260 || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2261 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2264 str[ d++ ] = val->bv_val[ s++ ];
2274 * Length of the (supposedly) DCE string representation,
2275 * accounting for escaped hex of UTF-8 chars
2278 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2287 if ( val->bv_len == 0 ) {
2291 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2293 * FIXME: Turn the value into a binary encoded BER?
2298 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2299 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2314 * convert to (supposedly) DCE string representation,
2315 * escaping with hex the UTF-8 stuff;
2316 * assume the destination has enough room for escaping
2319 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2327 if ( val->bv_len == 0 ) {
2332 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2334 * FIXME: Turn the value into a binary encoded BER?
2342 * we assume the string has enough room for the hex encoding
2346 for ( s = 0, d = 0; s < val->bv_len; ) {
2347 if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2350 str[ d++ ] = val->bv_val[ s++ ];
2360 * Length of the (supposedly) AD canonical string representation,
2361 * accounting for escaped hex of UTF-8 chars
2364 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2373 if ( val->bv_len == 0 ) {
2377 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2379 * FIXME: Turn the value into a binary encoded BER?
2384 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2385 if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2400 * convert to (supposedly) AD string representation,
2401 * escaping with hex the UTF-8 stuff;
2402 * assume the destination has enough room for escaping
2405 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2413 if ( val->bv_len == 0 ) {
2418 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2420 * FIXME: Turn the value into a binary encoded BER?
2428 * we assume the string has enough room for the hex encoding
2432 for ( s = 0, d = 0; s < val->bv_len; ) {
2433 if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2436 str[ d++ ] = val->bv_val[ s++ ];
2446 * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2447 * the forst part of the AD representation of the DN is written in DNS
2448 * form, i.e. dot separated domain name components (as suggested
2449 * by Luke Howard, http://www.padl.com/~lukeh)
2452 dn2domain( LDAPDN *dn, char *str, int *iRDN )
2455 int domain = 0, first = 1;
2456 ber_len_t l = 1; /* we move the null also */
2458 /* we are guaranteed there's enough memory in str */
2464 assert( *iRDN > 0 );
2466 for ( i = *iRDN; i >= 0; i-- ) {
2470 assert( dn[ i ][ 0 ] );
2473 assert( rdn[ 0 ][ 0 ] );
2474 ava = rdn[ 0 ][ 0 ];
2476 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2484 AC_MEMCPY( str, ava->la_value->bv_val,
2485 ava->la_value->bv_len + 1);
2486 l += ava->la_value->bv_len;
2489 AC_MEMCPY( str + ava->la_value->bv_len + 1, str, l);
2490 AC_MEMCPY( str, ava->la_value->bv_val,
2491 ava->la_value->bv_len );
2492 str[ ava->la_value->bv_len ] = '.';
2493 l += ava->la_value->bv_len + 1;
2503 rdn2strlen( LDAPRDN *rdn, ber_len_t *len,
2504 int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2511 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2512 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2514 /* len(type) + '=' + '+' | ',' */
2515 l += ava->la_attr->bv_len + 2;
2517 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2518 /* octothorpe + twice the length */
2519 l += 1 + 2 * ava->la_value->bv_len;
2524 if ( ( *s2l )( ava->la_value, ava->la_flags, &vl ) ) {
2537 rdn2str( LDAPRDN *rdn, char *str, ber_len_t *len,
2538 int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2543 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2544 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2546 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2547 ava->la_attr->bv_len );
2548 l += ava->la_attr->bv_len;
2552 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2554 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2557 l += 2 * ava->la_value->bv_len;
2562 if ( ( *s2s )( ava->la_value, &str[ l ],
2563 ava->la_flags, &vl ) ) {
2568 str[ l++ ] = ( rdn[ iAVA + 1 ] ? '+' : ',' );
2577 rdn2DCEstrlen( LDAPRDN *rdn, ber_len_t *len )
2584 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2585 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2587 /* len(type) + '=' + ',' | '/' */
2588 l += ava->la_attr->bv_len + 2;
2590 switch ( ava->la_flags ) {
2591 case LDAP_AVA_BINARY:
2592 /* octothorpe + twice the length */
2593 l += 1 + 2 * ava->la_value->bv_len;
2596 case LDAP_AVA_STRING: {
2599 if ( strval2DCEstrlen( ava->la_value,
2600 ava->la_flags, &vl ) ) {
2618 rdn2DCEstr( LDAPRDN *rdn, char *str, ber_len_t *len, int first )
2623 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2624 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2629 str[ l++ ] = ( iAVA ? ',' : '/' );
2632 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2633 ava->la_attr->bv_len );
2634 l += ava->la_attr->bv_len;
2638 switch ( ava->la_flags ) {
2639 case LDAP_AVA_BINARY:
2641 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2644 l += 2 * ava->la_value->bv_len;
2647 case LDAP_AVA_STRING: {
2650 if ( strval2DCEstr( ava->la_value, &str[ l ],
2651 ava->la_flags, &vl ) ) {
2669 rdn2UFNstrlen( LDAPRDN *rdn, ber_len_t *len )
2679 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2680 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2683 l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
2685 /* FIXME: are binary values allowed in UFN? */
2686 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2687 /* octothorpe + twice the value */
2688 l += 1 + 2 * ava->la_value->bv_len;
2693 if ( strval2strlen( ava->la_value, ava->la_flags,
2707 rdn2UFNstr( LDAPRDN *rdn, char *str, ber_len_t *len )
2712 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2713 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2715 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2717 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2720 l += 2 * ava->la_value->bv_len;
2725 if ( strval2str( ava->la_value, &str[ l ],
2726 ava->la_flags, &vl ) ) {
2732 if ( rdn[ iAVA + 1 ]) {
2733 AC_MEMCPY( &str[ l ], " + ", 3 );
2737 AC_MEMCPY( &str[ l ], ", ", 2 );
2748 rdn2ADstrlen( LDAPRDN *rdn, ber_len_t *len )
2758 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2759 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2764 /* FIXME: are binary values allowed in UFN? */
2765 switch ( ava->la_flags ) {
2766 case LDAP_AVA_BINARY:
2767 /* octothorpe + twice the value */
2768 l += 1 + 2 * ava->la_value->bv_len;
2771 case LDAP_AVA_STRING: {
2774 if ( strval2ADstrlen( ava->la_value,
2775 ava->la_flags, &vl ) ) {
2793 rdn2ADstr( LDAPRDN *rdn, char *str, ber_len_t *len, int first )
2798 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2799 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2804 str[ l++ ] = ( iAVA ? ',' : '/' );
2807 switch ( ava->la_flags ) {
2808 case LDAP_AVA_BINARY:
2810 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2813 l += 2 * ava->la_value->bv_len;
2816 case LDAP_AVA_STRING: {
2819 if ( strval2ADstr( ava->la_value, &str[ l ],
2820 ava->la_flags, &vl ) ) {
2840 * Returns in str a string representation of rdn based on flags.
2841 * There is some duplication of code between this and ldap_dn2str;
2842 * this is wanted to reduce the allocation of temporary buffers.
2845 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2852 if ( rdn == NULL ) {
2853 *str = LDAP_STRDUP( "" );
2854 return( LDAP_SUCCESS );
2858 * This routine wastes "back" bytes at the end of the string
2862 switch ( LDAP_DN_FORMAT( flags ) ) {
2863 case LDAP_DN_FORMAT_LDAPV3:
2864 if ( rdn2strlen( rdn, &l, strval2strlen ) ) {
2865 return( LDAP_OTHER );
2869 case LDAP_DN_FORMAT_LDAPV2:
2870 if ( rdn2strlen( rdn, &l, strval2IA5strlen ) ) {
2871 return( LDAP_OTHER );
2875 case LDAP_DN_FORMAT_UFN:
2876 if ( rdn2UFNstrlen( rdn, &l ) ) {
2877 return( LDAP_OTHER );
2881 case LDAP_DN_FORMAT_DCE:
2882 if ( rdn2DCEstrlen( rdn, &l ) ) {
2883 return( LDAP_OTHER );
2887 case LDAP_DN_FORMAT_AD_CANONICAL:
2888 if ( rdn2ADstrlen( rdn, &l ) ) {
2889 return( LDAP_OTHER );
2894 return( LDAP_OTHER );
2897 *str = LDAP_MALLOC( l + 1 );
2899 switch ( LDAP_DN_FORMAT( flags ) ) {
2900 case LDAP_DN_FORMAT_LDAPV3:
2901 rc = rdn2str( rdn, *str, &l, strval2str );
2905 case LDAP_DN_FORMAT_LDAPV2:
2906 rc = rdn2str( rdn, *str, &l, strval2IA5str );
2910 case LDAP_DN_FORMAT_UFN:
2911 rc = rdn2UFNstr( rdn, *str, &l );
2915 case LDAP_DN_FORMAT_DCE:
2916 rc = rdn2DCEstr( rdn, *str, &l, 1 );
2920 case LDAP_DN_FORMAT_AD_CANONICAL:
2921 rc = rdn2ADstr( rdn, *str, &l, 1 );
2926 /* need at least one of the previous */
2927 return( LDAP_OTHER );
2931 ldap_memfree( *str );
2932 return( LDAP_OTHER );
2935 ( *str )[ l - back ] = '\0';
2937 return( LDAP_SUCCESS );
2941 * Very bulk implementation; many optimizations can be performed
2942 * - a NULL dn results in an empty string ""
2945 * a) what do we do if a UTF-8 string must be converted in LDAPv2?
2946 * we must encode it in binary form ('#' + HEXPAIRs)
2947 * b) does DCE/AD support UTF-8?
2948 * no clue; don't think so.
2949 * c) what do we do when binary values must be converted in UTF/DCE/AD?
2950 * use binary encoded BER
2952 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
2955 int rc = LDAP_OTHER;
2958 /* stringifying helpers for LDAPv3/LDAPv2 */
2959 int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2960 int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2964 Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2str(%u)\n%s%s", flags, "", "" );
2969 * a null dn means an empty dn string
2970 * FIXME: better raise an error?
2973 *str = LDAP_STRDUP( "" );
2974 return( LDAP_SUCCESS );
2977 switch ( LDAP_DN_FORMAT( flags ) ) {
2978 case LDAP_DN_FORMAT_LDAPV3:
2979 sv2l = strval2strlen;
2983 case LDAP_DN_FORMAT_LDAPV2:
2984 sv2l = strval2IA5strlen;
2985 sv2s = strval2IA5str;
2988 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2990 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2992 if ( rdn2strlen( rdn, &rdnl, sv2l ) ) {
2993 goto return_results;
2999 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3000 rc = LDAP_NO_MEMORY;
3004 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
3006 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3008 if ( rdn2str( rdn, &( *str )[ l ], &rdnl, sv2s ) ) {
3011 goto return_results;
3019 * trim the last ',' (the allocated memory
3020 * is one byte longer than required)
3022 ( *str )[ len - 1 ] = '\0';
3027 case LDAP_DN_FORMAT_UFN: {
3030 * FIXME: quoting from RFC 1781:
3032 To take a distinguished name, and generate a name of this format with
3033 attribute types omitted, the following steps are followed.
3035 1. If the first attribute is of type CommonName, the type may be
3038 2. If the last attribute is of type Country, the type may be
3041 3. If the last attribute is of type Country, the last
3042 Organisation attribute may have the type omitted.
3044 4. All attributes of type OrganisationalUnit may have the type
3045 omitted, unless they are after an Organisation attribute or
3046 the first attribute is of type OrganisationalUnit.
3048 * this should be the pedantic implementation.
3050 * Here the standard implementation reflects
3051 * the one historically provided by OpenLDAP
3052 * (and UMIch, I presume), with the variant
3053 * of spaces and plusses (' + ') separating
3056 * A non-standard but nice implementation could
3057 * be to turn the final "dc" attributes into a
3058 * dot-separated domain.
3060 * Other improvements could involve the use of
3061 * friendly country names and so.
3064 int leftmost_dc = -1;
3066 #endif /* DC_IN_UFN */
3068 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3070 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3072 if ( rdn2UFNstrlen( rdn, &rdnl ) ) {
3073 goto return_results;
3078 if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
3079 if ( leftmost_dc == -1 ) {
3085 #endif /* DC_IN_UFN */
3088 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3089 rc = LDAP_NO_MEMORY;
3094 if ( leftmost_dc == -1 ) {
3095 #endif /* DC_IN_UFN */
3096 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
3098 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3100 if ( rdn2UFNstr( rdn, &( *str )[ l ], &vl ) ) {
3103 goto return_results;
3109 * trim the last ', ' (the allocated memory
3110 * is two bytes longer than required)
3112 ( *str )[ len - 2 ] = '\0';
3115 last_iRDN = iRDN - 1;
3117 for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
3119 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3121 if ( rdn2UFNstr( rdn, &( *str )[ l ], &vl ) ) {
3124 goto return_results;
3129 if ( !dn2domain( dn, &( *str )[ l ], &last_iRDN ) ) {
3132 goto return_results;
3135 /* the string is correctly terminated by dn2domain */
3137 #endif /* DC_IN_UFN */
3143 case LDAP_DN_FORMAT_DCE:
3145 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3147 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3149 if ( rdn2DCEstrlen( rdn, &rdnl ) ) {
3150 goto return_results;
3156 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3157 rc = LDAP_NO_MEMORY;
3161 for ( l = 0; iRDN--; ) {
3163 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3165 if ( rdn2DCEstr( rdn, &( *str )[ l ], &rdnl, 0 ) ) {
3168 goto return_results;
3175 ( *str )[ len ] = '\0';
3180 case LDAP_DN_FORMAT_AD_CANONICAL: {
3183 * Sort of UFN for DCE DNs: a slash ('/') separated
3184 * global->local DN with no types; strictly speaking,
3185 * the naming context should be a domain, which is
3186 * written in DNS-style, e.g. dot-deparated.
3190 * "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3194 * "microsoft.com/People/Bill,Gates"
3196 for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
3198 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3200 if ( rdn2ADstrlen( rdn, &rdnl ) ) {
3201 goto return_results;
3207 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3208 rc = LDAP_NO_MEMORY;
3213 if ( iRDN && dn2domain( dn, *str, &iRDN ) ) {
3214 for ( l = strlen( *str ); iRDN >= 0 ; iRDN-- ) {
3216 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3218 if ( rdn2ADstr( rdn, &( *str )[ l ],
3222 goto return_results;
3231 * Strictly speaking, AD canonical requires
3232 * a DN to be in the form "..., dc=smtg",
3233 * i.e. terminated by a domain component
3235 if ( flags & LDAP_DN_PEDANTIC ) {
3238 rc = LDAP_INVALID_DN_SYNTAX;
3242 for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3244 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3246 if ( rdn2ADstr( rdn, &( *str )[ l ],
3250 goto return_results;
3259 ( *str )[ len ] = '\0';
3270 Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2str(%s,%u)=%d\n", *str, flags, rc );