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 char *dn2dn( const char *dnin, unsigned fin, 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 LDAPAVA * ldapava_new( const struct berval *attr, const struct berval *val,
70 void ldapava_free( LDAPAVA *ava );
71 LDAPRDN * ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava );
72 LDAPRDN * ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where );
73 /* void ldapava_free_rdn( LDAPRDN *rdn ); in ldap.h */
74 LDAPDN * ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn );
75 LDAPDN * ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where );
76 /* void ldapava_free_dn( LDAPDN *dn ); in ldap.h */
78 /* Higher level helpers */
79 static int rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
80 int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
81 static int rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
82 int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
83 static int rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
84 static int rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len );
85 static int rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
86 static int rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flag, ber_len_t *len, int first );
87 static int rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
88 static int rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first );
90 #ifndef USE_LDAP_DN_PARSING /* deprecated */
91 #define NAME_TYPE_LDAP_RDN 0
92 #define NAME_TYPE_LDAP_DN 1
93 #define NAME_TYPE_DCE_DN 2
95 static char **explode_name( const char *name, int notypes, int is_type );
96 #endif /* !USE_LDAP_DN_PARSING */
99 * RFC 1823 ldap_get_dn
102 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
107 Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
109 if ( entry == NULL ) {
110 ld->ld_errno = LDAP_PARAM_ERROR;
114 tmp = *entry->lm_ber; /* struct copy */
115 if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
116 ld->ld_errno = LDAP_DECODING_ERROR;
124 * RFC 1823 ldap_dn2ufn
127 ldap_dn2ufn( LDAP_CONST char *dn )
129 #ifndef USE_LDAP_DN_PARSING /* deprecated */
134 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
136 /* produces completely untyped UFNs */
142 vals = ldap_explode_dn( dn , 0 );
147 for ( i = 0; vals[i]; i++ ) {
150 rvals = ldap_explode_rdn( vals[i] , 1 );
151 if ( rvals == NULL ) {
156 LDAP_FREE( vals[i] );
157 vals[i] = ldap_charray2str( rvals, " + " );
161 ufn = ldap_charray2str( vals, ", " );
165 #else /* USE_LDAP_DN_PARSING */
166 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
168 return dn2dn( dn, LDAP_DN_FORMAT_LDAPV3, LDAP_DN_FORMAT_UFN );
169 #endif /* USE_LDAP_DN_PARSING */
173 * RFC 1823 ldap_explode_dn
176 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
178 #ifndef USE_LDAP_DN_PARSING /* deprecated */
179 Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
181 return explode_name( dn, notypes, NAME_TYPE_LDAP_DN );
182 #else /* USE_LDAP_DN_PARSING */
184 char **values = NULL;
186 unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
188 Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
190 if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAPV3 )
195 for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) {
196 char *str, **v = NULL;
198 ldap_rdn2str( tmpDN[ iRDN ][ 0 ], &str, flag );
200 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iRDN ) );
202 LBER_VFREE( values );
203 ldapava_free_dn( tmpDN );
207 values[ iRDN ] = str;
209 values[ iRDN ] = NULL;
212 #endif /* USE_LDAP_DN_PARSING */
216 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
218 #ifndef USE_LDAP_DN_PARSING /* deprecated */
219 Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
221 return explode_name( rdn, notypes, NAME_TYPE_LDAP_RDN );
222 #else /* USE_LDAP_DN_PARSING */
224 char **values = NULL;
226 unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
228 Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
231 * we assume this dn is made of one rdn only
233 if ( ldap_str2dn( rdn, &tmpDN, LDAP_DN_FORMAT_LDAPV3 )
238 for ( iAVA = 0; tmpDN[ 0 ][ 0 ][ iAVA ]; iAVA++ ) {
239 ber_len_t l = 0, vl, al = 0;
240 char *str, **v = NULL;
241 LDAPAVA *ava = tmpDN[ 0 ][ 0 ][ iAVA ][ 0 ];
243 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iAVA ) );
249 if ( ava->la_flags == LDAP_AVA_BINARY ) {
250 vl = 1 + 2 * ava->la_value->bv_len;
253 if ( strval2strlen( ava->la_value,
254 ava->la_flags, &vl ) ) {
260 al = ava->la_attr->bv_len;
261 l = vl + ava->la_attr->bv_len + 1;
263 str = LDAP_MALLOC( l + 1 );
264 AC_MEMCPY( str, ava->la_attr->bv_val,
265 ava->la_attr->bv_len );
270 str = LDAP_MALLOC( l + 1 );
273 if ( ava->la_flags == LDAP_AVA_BINARY ) {
275 if ( binval2hexstr( ava->la_value, &str[ al ] ) ) {
280 if ( strval2str( ava->la_value, &str[ al ],
281 ava->la_flags, &vl ) ) {
287 values[ iAVA ] = str;
289 values[ iAVA ] = NULL;
291 ldapava_free_dn( tmpDN );
296 LBER_VFREE( values );
297 ldapava_free_dn( tmpDN );
299 #endif /* USE_LDAP_DN_PARSING */
303 ldap_dn2dcedn( LDAP_CONST char *dn )
305 #ifndef USE_LDAP_DN_PARSING /* deprecated */
306 char *dce, *q, **rdns, **p;
309 Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
311 rdns = explode_name( dn, 0, NAME_TYPE_LDAP_DN );
312 if ( rdns == NULL ) {
316 for ( p = rdns; *p != NULL; p++ ) {
317 len += strlen( *p ) + 1;
320 q = dce = LDAP_MALLOC( len + 1 );
325 p--; /* get back past NULL */
327 for ( ; p != rdns; p-- ) {
339 #else /* USE_LDAP_DN_PARSING */
340 Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
342 return dn2dn( dn, LDAP_DN_FORMAT_LDAPV3, LDAP_DN_FORMAT_DCE );
343 #endif /* USE_LDAP_DN_PARSING */
347 ldap_dcedn2dn( LDAP_CONST char *dce )
349 #ifndef USE_LDAP_DN_PARSING
350 char *dn, *q, **rdns, **p;
353 Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
355 rdns = explode_name( dce, 0, NAME_TYPE_DCE_DN );
356 if ( rdns == NULL ) {
362 for ( p = rdns; *p != NULL; p++ ) {
363 len += strlen( *p ) + 1;
366 q = dn = LDAP_MALLOC( len );
373 for ( ; p != rdns; p-- ) {
381 /* the name was fully qualified, thus the most-significant
382 * RDN was empty. trash the last comma */
386 /* the name was relative. copy the most significant RDN */
391 #else /* USE_LDAP_DN_PARSING */
392 Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
394 return dn2dn( dce, LDAP_DN_FORMAT_DCE, LDAP_DN_FORMAT_LDAPV3 );
395 #endif /* USE_LDAP_DN_PARSING */
399 ldap_dn2ad_canonical( LDAP_CONST char *dn )
401 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
403 return dn2dn( dn, LDAP_DN_FORMAT_LDAPV3, LDAP_DN_FORMAT_AD_CANONICAL );
406 #ifndef USE_LDAP_DN_PARSING /* deprecated */
411 explode_name( const char *name, int notypes, int is_type )
413 const char *p, *q, *rdn;
415 int offset, state, have_equals, count = 0, endquote, len;
418 if(name == NULL) name = "";
420 /* skip leading whitespace */
421 while( ldap_utf8_isspace( name )) {
422 LDAP_UTF8_INCR( name );
437 if ( p[1] != '\0' ) {
438 offset = LDAP_UTF8_OFFSET(++p);
442 if ( state == INQUOTE )
448 if( state == OUTQUOTE ) have_equals++;
451 if (is_type == NAME_TYPE_LDAP_RDN)
455 if (is_type == NAME_TYPE_DCE_DN)
460 if (is_type == NAME_TYPE_LDAP_DN)
465 if ( state == OUTQUOTE ) {
469 if ( parts == NULL ) {
470 if (( parts = (char **)LDAP_MALLOC( 8
471 * sizeof( char *))) == NULL )
473 } else if ( count >= 8 ) {
474 if (( parts = (char **)LDAP_REALLOC( parts,
475 (count+1) * sizeof( char *)))
480 parts[ count ] = NULL;
484 for ( q = rdn; q < p && *q != '='; ++q ) {
496 if ( p[-1] == '"' ) {
504 if (( parts[ count-1 ] = (char *)LDAP_CALLOC( 1,
507 AC_MEMCPY( parts[ count-1 ], rdn, len );
510 /* skip trailing spaces */
511 while( len > 0 && ldap_utf8_isspace(
512 &parts[count-1][len-1] ) )
518 parts[ count-1 ][ len ] = '\0';
522 * Don't forget to increment 'p' back to where
523 * it should be. If we don't, then we will
524 * never get past an "end quote."
529 rdn = *p ? &p[1] : p;
530 while ( ldap_utf8_isspace( rdn ) )
538 #endif /* !USE_LDAP_DN_PARSING */
541 * helper that changes the string representation of dnin
542 * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
545 * LDAP_DN_FORMAT_LDAPV3 (rfc 2253 and ldapbis)
546 * LDAP_DN_FORMAT_LDAPV2 (rfc 1779)
547 * LDAP_DN_FORMAT_DCE (?)
549 * fout can be any of the above plus:
550 * LDAP_DN_FORMAT_UFN (rfc 1781, partial and with extensions)
551 * LDAP_DN_FORMAT_AD_CANONICAL (?)
554 dn2dn( const char *dnin, unsigned fin, unsigned fout )
557 LDAPDN *tmpDN = NULL;
563 if ( ldap_str2dn( dnin , &tmpDN, fin ) != LDAP_SUCCESS ) {
567 /* don't care about the result ... */
568 ldap_dn2str( tmpDN, &dnout, fout );
570 ldapava_free_dn( tmpDN );
578 /* #define B4ATTRTYPE 0x0001 */
579 #define B4OIDATTRTYPE 0x0002
580 #define B4STRINGATTRTYPE 0x0003
582 #define B4AVAEQUALS 0x0100
583 #define B4AVASEP 0x0200
584 #define B4RDNSEP 0x0300
585 #define GOTAVA 0x0400
587 #define B4ATTRVALUE 0x0010
588 #define B4STRINGVALUE 0x0020
589 #define B4IA5VALUEQUOTED 0x0030
590 #define B4IA5VALUE 0x0040
591 #define B4BINARYVALUE 0x0050
593 /* Helpers (mostly from slapd.h; maybe it should be rewritten from this) */
594 #define LDAP_DN_ASCII_SPACE(c) \
595 ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
596 #define LDAP_DN_ASCII_LOWER(c) ( (c) >= 'a' && (c) <= 'z' )
597 #define LDAP_DN_ASCII_UPPER(c) ( (c) >= 'A' && (c) <= 'Z' )
598 #define LDAP_DN_ASCII_ALPHA(c) \
599 ( LDAP_DN_ASCII_LOWER(c) || LDAP_DN_ASCII_UPPER(c) )
600 #define LDAP_DN_ASCII_DIGIT(c) ( (c) >= '0' && (c) <= '9' )
601 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) ( (c) >= 'a' && (c) <= 'f' )
602 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) ( (c) >= 'A' && (c) <= 'F' )
603 #define LDAP_DN_ASCII_HEXDIGIT(c) \
604 ( LDAP_DN_ASCII_DIGIT(c) \
605 || LDAP_DN_ASCII_LCASE_HEXALPHA(c) \
606 || LDAP_DN_ASCII_UCASE_HEXALPHA(c) )
607 #define LDAP_DN_ASCII_ALNUM(c) \
608 ( LDAP_DN_ASCII_ALPHA(c) || LDAP_DN_ASCII_DIGIT(c) )
609 #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' )
612 #define LDAP_DN_OID_LEADCHAR(c) ( LDAP_DN_ASCII_DIGIT(c) )
613 #define LDAP_DN_DESC_LEADCHAR(c) ( LDAP_DN_ASCII_ALPHA(c) )
614 #define LDAP_DN_DESC_CHAR(c) ( LDAP_DN_ASCII_ALNUM(c) || (c) == '-' )
615 #define LDAP_DN_LANG_SEP(c) ( (c) == ';' )
616 #define LDAP_DN_ATTRDESC_CHAR(c) \
617 ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
619 /* special symbols */
620 #define LDAP_DN_AVA_EQUALS(c) ( (c) == '=' )
621 #define LDAP_DN_AVA_SEP(c) ( (c) == '+' )
622 #define LDAP_DN_RDN_SEP(c) ( (c) == ',' )
623 #define LDAP_DN_RDN_SEP_V2(c) ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
624 #define LDAP_DN_OCTOTHORPE(c) ( (c) == '#' )
625 #define LDAP_DN_QUOTES(c) ( (c) == '\"' )
626 #define LDAP_DN_ESCAPE(c) ( (c) == '\\' )
627 #define LDAP_DN_VALUE_END(c) \
628 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
629 #define LDAP_DN_NE(c) \
630 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
631 || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
632 #define LDAP_DN_NEEDESCAPE(c) \
633 ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
634 #define LDAP_DN_NEEDESCAPE_LEAD(c) \
635 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) )
636 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
637 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
638 #define LDAP_DN_WILLESCAPE_CHAR( c) \
639 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
640 #define LDAP_DN_WILLESCAPE(f, c) \
641 ( ( !( (f) & LDAP_DN_PRETTY ) ) && LDAP_DN_WILLESCAPE_CHAR(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( flags, 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( flags, 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, unsigned flags, 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;
2523 unsigned f = flags | ava->la_flags;
2525 if ( ( *s2l )( ava->la_value, f, &vl ) ) {
2538 rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
2539 int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2544 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2545 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2547 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2548 ava->la_attr->bv_len );
2549 l += ava->la_attr->bv_len;
2553 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2555 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2558 l += 2 * ava->la_value->bv_len;
2562 unsigned f = flags | ava->la_flags;
2564 if ( ( *s2s )( ava->la_value, &str[ l ], f, &vl ) ) {
2569 str[ l++ ] = ( rdn[ iAVA + 1 ] ? '+' : ',' );
2578 rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2585 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2586 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2588 /* len(type) + '=' + ',' | '/' */
2589 l += ava->la_attr->bv_len + 2;
2591 switch ( ava->la_flags ) {
2592 case LDAP_AVA_BINARY:
2593 /* octothorpe + twice the length */
2594 l += 1 + 2 * ava->la_value->bv_len;
2597 case LDAP_AVA_STRING: {
2599 unsigned f = flags | ava->la_flags;
2601 if ( strval2DCEstrlen( ava->la_value, f, &vl ) ) {
2619 rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2624 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2625 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2630 str[ l++ ] = ( iAVA ? ',' : '/' );
2633 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2634 ava->la_attr->bv_len );
2635 l += ava->la_attr->bv_len;
2639 switch ( ava->la_flags ) {
2640 case LDAP_AVA_BINARY:
2642 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2645 l += 2 * ava->la_value->bv_len;
2648 case LDAP_AVA_STRING: {
2650 unsigned f = flags | ava->la_flags;
2652 if ( strval2DCEstr( ava->la_value, &str[ l ], f, &vl ) ) {
2670 rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2680 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2681 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2684 l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
2686 /* FIXME: are binary values allowed in UFN? */
2687 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2688 /* octothorpe + twice the value */
2689 l += 1 + 2 * ava->la_value->bv_len;
2693 unsigned f = flags | ava->la_flags;
2695 if ( strval2strlen( ava->la_value, f, &vl ) ) {
2708 rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
2713 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2714 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2716 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2718 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2721 l += 2 * ava->la_value->bv_len;
2725 unsigned f = flags | ava->la_flags;
2727 if ( strval2str( ava->la_value, &str[ l ], f, &vl ) ) {
2733 if ( rdn[ iAVA + 1 ]) {
2734 AC_MEMCPY( &str[ l ], " + ", 3 );
2738 AC_MEMCPY( &str[ l ], ", ", 2 );
2749 rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2759 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2760 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2765 /* FIXME: are binary values allowed in UFN? */
2766 switch ( ava->la_flags ) {
2767 case LDAP_AVA_BINARY:
2768 /* octothorpe + twice the value */
2769 l += 1 + 2 * ava->la_value->bv_len;
2772 case LDAP_AVA_STRING: {
2774 unsigned f = flags | ava->la_flags;
2776 if ( strval2ADstrlen( ava->la_value, f, &vl ) ) {
2794 rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2799 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2800 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2805 str[ l++ ] = ( iAVA ? ',' : '/' );
2808 switch ( ava->la_flags ) {
2809 case LDAP_AVA_BINARY:
2811 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2814 l += 2 * ava->la_value->bv_len;
2817 case LDAP_AVA_STRING: {
2819 unsigned f = flags | ava->la_flags;
2821 if ( strval2ADstr( ava->la_value, &str[ l ], f, &vl ) ) {
2841 * Returns in str a string representation of rdn based on flags.
2842 * There is some duplication of code between this and ldap_dn2str;
2843 * this is wanted to reduce the allocation of temporary buffers.
2846 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2853 if ( rdn == NULL ) {
2854 *str = LDAP_STRDUP( "" );
2855 return( LDAP_SUCCESS );
2859 * This routine wastes "back" bytes at the end of the string
2863 switch ( LDAP_DN_FORMAT( flags ) ) {
2864 case LDAP_DN_FORMAT_LDAPV3:
2865 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2866 return( LDAP_OTHER );
2870 case LDAP_DN_FORMAT_LDAPV2:
2871 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2872 return( LDAP_OTHER );
2876 case LDAP_DN_FORMAT_UFN:
2877 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2878 return( LDAP_OTHER );
2882 case LDAP_DN_FORMAT_DCE:
2883 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2884 return( LDAP_OTHER );
2888 case LDAP_DN_FORMAT_AD_CANONICAL:
2889 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2890 return( LDAP_OTHER );
2895 return( LDAP_OTHER );
2898 *str = LDAP_MALLOC( l + 1 );
2900 switch ( LDAP_DN_FORMAT( flags ) ) {
2901 case LDAP_DN_FORMAT_LDAPV3:
2902 rc = rdn2str( rdn, *str, flags, &l, strval2str );
2906 case LDAP_DN_FORMAT_LDAPV2:
2907 rc = rdn2str( rdn, *str, flags, &l, strval2IA5str );
2911 case LDAP_DN_FORMAT_UFN:
2912 rc = rdn2UFNstr( rdn, *str, flags, &l );
2916 case LDAP_DN_FORMAT_DCE:
2917 rc = rdn2DCEstr( rdn, *str, flags, &l, 1 );
2921 case LDAP_DN_FORMAT_AD_CANONICAL:
2922 rc = rdn2ADstr( rdn, *str, flags, &l, 1 );
2927 /* need at least one of the previous */
2928 return( LDAP_OTHER );
2932 ldap_memfree( *str );
2933 return( LDAP_OTHER );
2936 ( *str )[ l - back ] = '\0';
2938 return( LDAP_SUCCESS );
2942 * Very bulk implementation; many optimizations can be performed
2943 * - a NULL dn results in an empty string ""
2946 * a) what do we do if a UTF-8 string must be converted in LDAPv2?
2947 * we must encode it in binary form ('#' + HEXPAIRs)
2948 * b) does DCE/AD support UTF-8?
2949 * no clue; don't think so.
2950 * c) what do we do when binary values must be converted in UTF/DCE/AD?
2951 * use binary encoded BER
2953 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
2956 int rc = LDAP_OTHER;
2959 /* stringifying helpers for LDAPv3/LDAPv2 */
2960 int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2961 int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2965 Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2str(%u)\n%s%s", flags, "", "" );
2970 * a null dn means an empty dn string
2971 * FIXME: better raise an error?
2974 *str = LDAP_STRDUP( "" );
2975 return( LDAP_SUCCESS );
2978 switch ( LDAP_DN_FORMAT( flags ) ) {
2979 case LDAP_DN_FORMAT_LDAPV3:
2980 sv2l = strval2strlen;
2984 case LDAP_DN_FORMAT_LDAPV2:
2985 sv2l = strval2IA5strlen;
2986 sv2s = strval2IA5str;
2989 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2991 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2993 if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
2994 goto return_results;
3000 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3001 rc = LDAP_NO_MEMORY;
3005 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
3007 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3009 if ( rdn2str( rdn, &( *str )[ l ], flags,
3013 goto return_results;
3021 * trim the last ',' (the allocated memory
3022 * is one byte longer than required)
3024 ( *str )[ len - 1 ] = '\0';
3029 case LDAP_DN_FORMAT_UFN: {
3032 * FIXME: quoting from RFC 1781:
3034 To take a distinguished name, and generate a name of this format with
3035 attribute types omitted, the following steps are followed.
3037 1. If the first attribute is of type CommonName, the type may be
3040 2. If the last attribute is of type Country, the type may be
3043 3. If the last attribute is of type Country, the last
3044 Organisation attribute may have the type omitted.
3046 4. All attributes of type OrganisationalUnit may have the type
3047 omitted, unless they are after an Organisation attribute or
3048 the first attribute is of type OrganisationalUnit.
3050 * this should be the pedantic implementation.
3052 * Here the standard implementation reflects
3053 * the one historically provided by OpenLDAP
3054 * (and UMIch, I presume), with the variant
3055 * of spaces and plusses (' + ') separating
3058 * A non-standard but nice implementation could
3059 * be to turn the final "dc" attributes into a
3060 * dot-separated domain.
3062 * Other improvements could involve the use of
3063 * friendly country names and so.
3066 int leftmost_dc = -1;
3068 #endif /* DC_IN_UFN */
3070 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3072 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3074 if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
3075 goto return_results;
3080 if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
3081 if ( leftmost_dc == -1 ) {
3087 #endif /* DC_IN_UFN */
3090 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3091 rc = LDAP_NO_MEMORY;
3096 if ( leftmost_dc == -1 ) {
3097 #endif /* DC_IN_UFN */
3098 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
3100 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3102 if ( rdn2UFNstr( rdn, &( *str )[ l ],
3106 goto return_results;
3112 * trim the last ', ' (the allocated memory
3113 * is two bytes longer than required)
3115 ( *str )[ len - 2 ] = '\0';
3118 last_iRDN = iRDN - 1;
3120 for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
3122 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3124 if ( rdn2UFNstr( rdn, &( *str )[ l ],
3128 goto return_results;
3133 if ( !dn2domain( dn, &( *str )[ l ], &last_iRDN ) ) {
3136 goto return_results;
3139 /* the string is correctly terminated by dn2domain */
3141 #endif /* DC_IN_UFN */
3147 case LDAP_DN_FORMAT_DCE:
3149 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3151 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3153 if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
3154 goto return_results;
3160 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3161 rc = LDAP_NO_MEMORY;
3165 for ( l = 0; iRDN--; ) {
3167 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3169 if ( rdn2DCEstr( rdn, &( *str )[ l ], flags,
3173 goto return_results;
3180 ( *str )[ len ] = '\0';
3185 case LDAP_DN_FORMAT_AD_CANONICAL: {
3188 * Sort of UFN for DCE DNs: a slash ('/') separated
3189 * global->local DN with no types; strictly speaking,
3190 * the naming context should be a domain, which is
3191 * written in DNS-style, e.g. dot-deparated.
3195 * "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3199 * "microsoft.com/People/Bill,Gates"
3201 for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
3203 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3205 if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
3206 goto return_results;
3212 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3213 rc = LDAP_NO_MEMORY;
3218 if ( iRDN && dn2domain( dn, *str, &iRDN ) ) {
3219 for ( l = strlen( *str ); iRDN >= 0 ; iRDN-- ) {
3221 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3223 if ( rdn2ADstr( rdn, &( *str )[ l ],
3224 flags, &rdnl, 0 ) ) {
3227 goto return_results;
3236 * Strictly speaking, AD canonical requires
3237 * a DN to be in the form "..., dc=smtg",
3238 * i.e. terminated by a domain component
3240 if ( flags & LDAP_DN_PEDANTIC ) {
3243 rc = LDAP_INVALID_DN_SYNTAX;
3247 for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3249 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3251 if ( rdn2ADstr( rdn, &( *str )[ l ],
3252 flags, &rdnl, first ) ) {
3255 goto return_results;
3264 ( *str )[ len ] = '\0';
3275 Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2str(%s,%u)=%d\n", *str, flags, rc );