3 * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * Copyright (c) 1994 Regents of the University of Michigan.
17 #include <ac/stdlib.h>
20 #include <ac/socket.h>
21 #include <ac/string.h>
26 /* extension to UFN that turns trailing "dc=value" rdns in DNS style,
27 * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */
30 static int dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout );
32 /* from libraries/libldap/schema.c */
33 extern char * parse_numericoid(const char **sp, int *code, const int flags);
35 /* parsing/printing routines */
36 static int str2strval( const char *str, struct berval **val,
37 const char **next, unsigned flags, unsigned *retFlags );
38 static int DCE2strval( const char *str, struct berval **val,
39 const char **next, unsigned flags );
40 static int IA52strval( const char *str, struct berval **val,
41 const char **next, unsigned flags );
42 static int quotedIA52strval( const char *str, struct berval **val,
43 const char **next, unsigned flags );
44 static int hexstr2binval( const char *str, struct berval **val,
45 const char **next, unsigned flags );
46 static int hexstr2bin( const char *str, char *c );
47 static int byte2hexpair( const char *val, char *pair );
48 static int binval2hexstr( struct berval *val, char *str );
49 static int strval2strlen( struct berval *val, unsigned flags,
51 static int strval2str( struct berval *val, char *str, unsigned flags,
53 static int strval2IA5strlen( struct berval *val, unsigned flags,
55 static int strval2IA5str( struct berval *val, char *str, unsigned flags,
57 static int strval2DCEstrlen( struct berval *val, unsigned flags,
59 static int strval2DCEstr( struct berval *val, char *str, unsigned flags,
61 static int strval2ADstrlen( struct berval *val, unsigned flags,
63 static int strval2ADstr( struct berval *val, char *str, unsigned flags,
65 static int dn2domain( LDAPDN *dn, char *str, int *iRDN );
68 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 */
168 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
170 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_UFN );
173 #endif /* USE_LDAP_DN_PARSING */
177 * RFC 1823 ldap_explode_dn
180 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
182 #ifndef USE_LDAP_DN_PARSING /* deprecated */
183 Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
185 return explode_name( dn, notypes, NAME_TYPE_LDAP_DN );
186 #else /* USE_LDAP_DN_PARSING */
188 char **values = NULL;
190 unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
192 Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
194 if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP )
199 for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) {
200 char *str, **v = NULL;
202 ldap_rdn2str( tmpDN[ iRDN ][ 0 ], &str, flag );
204 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iRDN ) );
206 LBER_VFREE( values );
207 ldapava_free_dn( tmpDN );
211 values[ iRDN ] = str;
213 values[ iRDN ] = NULL;
216 #endif /* USE_LDAP_DN_PARSING */
220 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
222 #ifndef USE_LDAP_DN_PARSING /* deprecated */
223 Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
225 return explode_name( rdn, notypes, NAME_TYPE_LDAP_RDN );
226 #else /* USE_LDAP_DN_PARSING */
228 char **values = NULL;
230 unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
232 Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
235 * we assume this dn is made of one rdn only
237 if ( ldap_str2dn( rdn, &tmpDN, LDAP_DN_FORMAT_LDAP )
242 for ( iAVA = 0; tmpDN[ 0 ][ 0 ][ iAVA ]; iAVA++ ) {
243 ber_len_t l = 0, vl, al = 0;
244 char *str, **v = NULL;
245 LDAPAVA *ava = tmpDN[ 0 ][ 0 ][ iAVA ][ 0 ];
247 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iAVA ) );
253 if ( ava->la_flags == LDAP_AVA_BINARY ) {
254 vl = 1 + 2 * ava->la_value->bv_len;
257 if ( strval2strlen( ava->la_value,
258 ava->la_flags, &vl ) ) {
264 al = ava->la_attr->bv_len;
265 l = vl + ava->la_attr->bv_len + 1;
267 str = LDAP_MALLOC( l + 1 );
268 AC_MEMCPY( str, ava->la_attr->bv_val,
269 ava->la_attr->bv_len );
274 str = LDAP_MALLOC( l + 1 );
277 if ( ava->la_flags == LDAP_AVA_BINARY ) {
279 if ( binval2hexstr( ava->la_value, &str[ al ] ) ) {
284 if ( strval2str( ava->la_value, &str[ al ],
285 ava->la_flags, &vl ) ) {
291 values[ iAVA ] = str;
293 values[ iAVA ] = NULL;
295 ldapava_free_dn( tmpDN );
300 LBER_VFREE( values );
301 ldapava_free_dn( tmpDN );
303 #endif /* USE_LDAP_DN_PARSING */
307 ldap_dn2dcedn( LDAP_CONST char *dn )
309 #ifndef USE_LDAP_DN_PARSING /* deprecated */
310 char *dce, *q, **rdns, **p;
313 Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
315 rdns = explode_name( dn, 0, NAME_TYPE_LDAP_DN );
316 if ( rdns == NULL ) {
320 for ( p = rdns; *p != NULL; p++ ) {
321 len += strlen( *p ) + 1;
324 q = dce = LDAP_MALLOC( len + 1 );
329 p--; /* get back past NULL */
331 for ( ; p != rdns; p-- ) {
343 #else /* USE_LDAP_DN_PARSING */
346 Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
348 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_DCE );
351 #endif /* USE_LDAP_DN_PARSING */
355 ldap_dcedn2dn( LDAP_CONST char *dce )
357 #ifndef USE_LDAP_DN_PARSING
358 char *dn, *q, **rdns, **p;
361 Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
363 rdns = explode_name( dce, 0, NAME_TYPE_DCE_DN );
364 if ( rdns == NULL ) {
370 for ( p = rdns; *p != NULL; p++ ) {
371 len += strlen( *p ) + 1;
374 q = dn = LDAP_MALLOC( len );
381 for ( ; p != rdns; p-- ) {
389 /* the name was fully qualified, thus the most-significant
390 * RDN was empty. trash the last comma */
394 /* the name was relative. copy the most significant RDN */
399 #else /* USE_LDAP_DN_PARSING */
402 Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
404 ( void )dn2dn( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
407 #endif /* USE_LDAP_DN_PARSING */
411 ldap_dn2ad_canonical( LDAP_CONST char *dn )
415 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
417 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP,
418 &out, LDAP_DN_FORMAT_AD_CANONICAL );
423 #ifndef USE_LDAP_DN_PARSING /* deprecated */
428 explode_name( const char *name, int notypes, int is_type )
430 const char *p, *q, *rdn;
432 int offset, state, have_equals, count = 0, endquote, len;
435 if(name == NULL) name = "";
437 /* skip leading whitespace */
438 while( ldap_utf8_isspace( name )) {
439 LDAP_UTF8_INCR( name );
454 if ( p[1] != '\0' ) {
455 offset = LDAP_UTF8_OFFSET(++p);
459 if ( state == INQUOTE )
465 if( state == OUTQUOTE ) have_equals++;
468 if (is_type == NAME_TYPE_LDAP_RDN)
472 if (is_type == NAME_TYPE_DCE_DN)
477 if (is_type == NAME_TYPE_LDAP_DN)
482 if ( state == OUTQUOTE ) {
486 if ( parts == NULL ) {
487 if (( parts = (char **)LDAP_MALLOC( 8
488 * sizeof( char *))) == NULL )
490 } else if ( count >= 8 ) {
491 if (( parts = (char **)LDAP_REALLOC( parts,
492 (count+1) * sizeof( char *)))
497 parts[ count ] = NULL;
501 for ( q = rdn; q < p && *q != '='; ++q ) {
513 if ( p[-1] == '"' ) {
521 if (( parts[ count-1 ] = (char *)LDAP_CALLOC( 1,
524 AC_MEMCPY( parts[ count-1 ], rdn, len );
527 /* skip trailing spaces */
528 while( len > 0 && ldap_utf8_isspace(
529 &parts[count-1][len-1] ) )
535 parts[ count-1 ][ len ] = '\0';
539 * Don't forget to increment 'p' back to where
540 * it should be. If we don't, then we will
541 * never get past an "end quote."
546 rdn = *p ? &p[1] : p;
547 while ( ldap_utf8_isspace( rdn ) )
555 #endif /* !USE_LDAP_DN_PARSING */
558 ldap_dn_normalize( const char *in, unsigned iflags, char **out, unsigned oflags )
562 #ifdef USE_LDAP_DN_PARSING
563 Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );
565 return dn2dn( in, iflags, out, oflags);
566 #else /* !USE_LDAP_DN_PARSING */
567 return( LDAP_OTHER );
568 #endif /* !USE_LDAP_DN_PARSING */
572 * helper that changes the string representation of dnin
573 * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
576 * LDAP_DN_FORMAT_LDAP (rfc 2253 and ldapbis liberal,
577 * plus some rfc 1779)
578 * LDAP_DN_FORMAT_LDAPV3 (rfc 2253 and ldapbis)
579 * LDAP_DN_FORMAT_LDAPV2 (rfc 1779)
580 * LDAP_DN_FORMAT_DCE (?)
582 * fout can be any of the above except
583 * LDAP_DN_FORMAT_LDAP
585 * LDAP_DN_FORMAT_UFN (rfc 1781, partial and with extensions)
586 * LDAP_DN_FORMAT_AD_CANONICAL (?)
589 dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout )
592 LDAPDN *tmpDN = NULL;
598 if ( dnin == NULL ) {
599 return( LDAP_SUCCESS );
602 rc = ldap_str2dn( dnin , &tmpDN, fin );
603 if ( rc != LDAP_SUCCESS ) {
607 rc = ldap_dn2str( tmpDN, dnout, fout );
609 ldapava_free_dn( tmpDN );
617 /* #define B4ATTRTYPE 0x0001 */
618 #define B4OIDATTRTYPE 0x0002
619 #define B4STRINGATTRTYPE 0x0003
621 #define B4AVAEQUALS 0x0100
622 #define B4AVASEP 0x0200
623 #define B4RDNSEP 0x0300
624 #define GOTAVA 0x0400
626 #define B4ATTRVALUE 0x0010
627 #define B4STRINGVALUE 0x0020
628 #define B4IA5VALUEQUOTED 0x0030
629 #define B4IA5VALUE 0x0040
630 #define B4BINARYVALUE 0x0050
632 /* Helpers (mostly from slapd.h; maybe it should be rewritten from this) */
633 #define LDAP_DN_ASCII_SPACE(c) \
634 ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
635 #define LDAP_DN_ASCII_LOWER(c) ( (c) >= 'a' && (c) <= 'z' )
636 #define LDAP_DN_ASCII_UPPER(c) ( (c) >= 'A' && (c) <= 'Z' )
637 #define LDAP_DN_ASCII_ALPHA(c) \
638 ( LDAP_DN_ASCII_LOWER(c) || LDAP_DN_ASCII_UPPER(c) )
639 #define LDAP_DN_ASCII_DIGIT(c) ( (c) >= '0' && (c) <= '9' )
640 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) ( (c) >= 'a' && (c) <= 'f' )
641 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) ( (c) >= 'A' && (c) <= 'F' )
642 #define LDAP_DN_ASCII_HEXDIGIT(c) \
643 ( LDAP_DN_ASCII_DIGIT(c) \
644 || LDAP_DN_ASCII_LCASE_HEXALPHA(c) \
645 || LDAP_DN_ASCII_UCASE_HEXALPHA(c) )
646 #define LDAP_DN_ASCII_ALNUM(c) \
647 ( LDAP_DN_ASCII_ALPHA(c) || LDAP_DN_ASCII_DIGIT(c) )
648 #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' )
651 #define LDAP_DN_OID_LEADCHAR(c) ( LDAP_DN_ASCII_DIGIT(c) )
652 #define LDAP_DN_DESC_LEADCHAR(c) ( LDAP_DN_ASCII_ALPHA(c) )
653 #define LDAP_DN_DESC_CHAR(c) ( LDAP_DN_ASCII_ALNUM(c) || (c) == '-' )
654 #define LDAP_DN_LANG_SEP(c) ( (c) == ';' )
655 #define LDAP_DN_ATTRDESC_CHAR(c) \
656 ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
658 /* special symbols */
659 #define LDAP_DN_AVA_EQUALS(c) ( (c) == '=' )
660 #define LDAP_DN_AVA_SEP(c) ( (c) == '+' )
661 #define LDAP_DN_RDN_SEP(c) ( (c) == ',' )
662 #define LDAP_DN_RDN_SEP_V2(c) ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
663 #define LDAP_DN_OCTOTHORPE(c) ( (c) == '#' )
664 #define LDAP_DN_QUOTES(c) ( (c) == '\"' )
665 #define LDAP_DN_ESCAPE(c) ( (c) == '\\' )
666 #define LDAP_DN_VALUE_END(c) \
667 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
668 #define LDAP_DN_NE(c) \
669 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
670 || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
671 #define LDAP_DN_NEEDESCAPE(c) \
672 ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
673 #define LDAP_DN_NEEDESCAPE_LEAD(c) \
674 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) )
675 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
676 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
677 #define LDAP_DN_WILLESCAPE_CHAR( c) \
678 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
679 #define LDAP_DN_WILLESCAPE(f, c) \
680 ( ( !( (f) & LDAP_DN_PRETTY ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
683 #define LDAP_DN_VALUE_END_V2(c) \
684 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
686 #define LDAP_DN_V2_SPECIAL(c) \
687 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
688 || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
689 || LDAP_DN_OCTOTHORPE(c) )
690 #define LDAP_DN_V2_PAIR(c) \
691 ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
694 * DCE (mostly from Luke Howard and IBM implementation for AIX)
696 * From: "Application Development Guide - Directory Services" (FIXME: add link?)
697 * Here escapes and valid chars for GDS are considered; as soon as more
698 * specific info is found, the macros will be updated.
700 * Chars: 'a'-'z', 'A'-'Z', '0'-'9',
701 * '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
703 * Metachars: '/', ',', '=', '\'.
705 * the '\' is used to escape other metachars.
711 * Attribute types must start with alphabetic chars and can contain
712 * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
714 #define LDAP_DN_RDN_SEP_DCE(c) ( (c) == '/' )
715 #define LDAP_DN_AVA_SEP_DCE(c) ( (c) == ',' )
716 #define LDAP_DN_ESCAPE_DCE(c) ( LDAP_DN_ESCAPE(c) )
717 #define LDAP_DN_VALUE_END_DCE(c) \
718 ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
719 #define LDAP_DN_NEEDESCAPE_DCE(c) \
720 ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
723 #define LDAP_DN_RDN_SEP_AD(c) ( (c) == '/' )
724 #define LDAP_DN_ESCAPE_AD(c) ( LDAP_DN_ESCAPE(c) )
725 #define LDAP_DN_AVA_SEP_AD(c) ( (c) == ',' ) /* assume same as DCE */
726 #define LDAP_DN_VALUE_END_AD(c) \
727 ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
728 #define LDAP_DN_NEEDESCAPE_AD(c) \
729 ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
732 #define LDAP_DN_HEXPAIR(s) \
733 ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
734 #define LDAP_DC_ATTR "dc"
735 /* better look at the AttributeDescription? */
737 /* FIXME: no composite rdn or non-"dc" types, right?
738 * (what about "dc" in OID form?) */
739 /* FIXME: we do not allow binary values in domain, right? */
740 /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
741 #define LDAP_DN_IS_RDN_DC( rdn ) \
742 ( ( rdn ) && ( rdn )[ 0 ][ 0 ] && !( rdn )[ 1 ] \
743 && ( ( rdn )[ 0 ][ 0 ]->la_flags == LDAP_AVA_STRING ) \
744 && ! strcasecmp( ( rdn )[ 0 ][ 0 ]->la_attr->bv_val, LDAP_DC_ATTR ) )
746 /* Composite rules */
747 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
748 ( LDAP_DN_LDAPV2(f) \
749 || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
750 #define LDAP_DN_ALLOW_SPACES(f) \
751 ( LDAP_DN_LDAPV2(f) \
752 || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
753 #define LDAP_DN_LDAP(f) \
754 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
755 #define LDAP_DN_LDAPV3(f) \
756 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
757 #define LDAP_DN_LDAPV2(f) \
758 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
759 #define LDAP_DN_DCE(f) \
760 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
761 #define LDAP_DN_UFN(f) \
762 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
763 #define LDAP_DN_ADC(f) \
764 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
765 #define LDAP_DN_FORMAT(f) ( (f) & LDAP_DN_FORMAT_MASK )
768 * LDAPAVA helpers (will become part of the API for operations
769 * on structural representations of DNs).
772 ldapava_new( const struct berval *attr, const struct berval *val,
780 ava = LDAP_MALLOC( sizeof( LDAPAVA ) );
782 /* should we test it? */
787 ava->la_attr = ( struct berval * )attr;
788 ava->la_value = ( struct berval * )val;
789 ava->la_flags = flags;
791 ava->la_private = NULL;
797 ldapava_free( LDAPAVA *ava )
801 ber_bvfree( ava->la_attr );
802 ber_bvfree( ava->la_value );
808 ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava )
816 for ( i = 0U; rdn[ i ]; i++ ) {
820 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
821 newRDN[ i ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
822 newRDN[ i ][ 0 ] = ava;
823 newRDN[ i + 1 ] = NULL;
829 ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where )
837 for ( i = 0U; rdn[ i ]; i++ ) {
843 /* assume "at end", which corresponds to
844 * ldapava_append_to_rdn */
847 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
849 /* data after insert point */
850 AC_MEMCPY( &newRDN[ where + 1 ], &newRDN[ where ],
851 ( i - where ) * sizeof( LDAPRDN * ) );
853 newRDN[ where ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
854 newRDN[ where ][ 0 ] = ava;
855 newRDN[ i + 1 ] = NULL;
861 ldapava_free_rdn( LDAPRDN *rdn )
869 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
870 assert( rdn[ iAVA ][ 0 ] );
872 ldapava_free( rdn[ iAVA ][ 0 ] );
879 ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn )
887 for ( i = 0U; dn[ i ]; i++ ) {
891 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
892 newDN[ i ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
893 newDN[ i ][ 0 ] = rdn;
894 newDN[ i + 1 ] = NULL;
900 ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where )
908 for ( i = 0U; dn[ i ]; i++ ) {
914 /* assume "at end", which corresponds to
915 * ldapava_append_to_dn */
918 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
920 /* data after insert point */
921 AC_MEMCPY( &newDN[ where + 1 ], &newDN[ where ],
922 ( i - where ) * sizeof( LDAPDN * ) );
924 newDN[ where ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
925 newDN[ where ][ 0 ] = rdn;
926 newDN[ i + 1 ] = NULL;
932 ldapava_free_dn( LDAPDN *dn )
940 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
941 assert( dn[ iRDN ][ 0 ] );
943 ldapava_free_rdn( dn[ iRDN ][ 0 ] );
950 * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
951 * into a structural representation of the DN, by separating attribute
952 * types and values encoded in the more appropriate form, which is
953 * string or OID for attribute types and binary form of the BER encoded
954 * value or Unicode string. Formats different from LDAPv3 are parsed
955 * according to their own rules and turned into the more appropriate
956 * form according to LDAPv3.
958 * NOTE: I realize the code is getting spaghettish; it is rather
959 * experimental and will hopefully turn into something more simple
960 * and readable as soon as it works as expected.
964 ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
967 int rc = LDAP_INVALID_DN_SYNTAX;
969 LDAPDN *newDN = NULL;
970 LDAPRDN *newRDN = NULL;
975 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );
979 switch ( LDAP_DN_FORMAT( flags ) ) {
980 case LDAP_DN_FORMAT_LDAP:
981 case LDAP_DN_FORMAT_LDAPV3:
982 case LDAP_DN_FORMAT_LDAPV2:
983 case LDAP_DN_FORMAT_DCE:
986 /* unsupported in str2dn */
987 case LDAP_DN_FORMAT_UFN:
988 case LDAP_DN_FORMAT_AD_CANONICAL:
989 return( LDAP_INVALID_DN_SYNTAX );
992 return( LDAP_OTHER );
995 if ( str[ 0 ] == '\0' ) {
996 return( LDAP_SUCCESS );
1000 if ( LDAP_DN_DCE( flags ) ) {
1003 * (from Luke Howard: thnx) A RDN separator is required
1004 * at the beginning of an (absolute) DN.
1006 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
1011 } else if ( LDAP_DN_LDAP( flags ) ) {
1013 * if dn starts with '/' let's make it a DCE dn
1015 if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
1016 flags |= LDAP_DN_FORMAT_DCE;
1021 for ( ; p[ 0 ]; p++ ) {
1025 err = ldap_str2rdn( p, &newRDN, &p, flags );
1026 if ( err != LDAP_SUCCESS ) {
1031 * We expect a rdn separator
1034 switch ( LDAP_DN_FORMAT( flags ) ) {
1035 case LDAP_DN_FORMAT_LDAPV3:
1036 if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
1042 case LDAP_DN_FORMAT_LDAP:
1043 case LDAP_DN_FORMAT_LDAPV2:
1044 if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
1050 case LDAP_DN_FORMAT_DCE:
1051 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
1060 if ( LDAP_DN_DCE( flags ) ) {
1061 /* add in reversed order */
1062 dn = ldapava_insert_into_dn( newDN, newRDN, 0 );
1064 dn = ldapava_append_to_dn( newDN, newRDN );
1068 rc = LDAP_NO_MEMORY;
1075 if ( p[ 0 ] == '\0' ) {
1078 * the DN is over, phew
1087 ldapava_free_rdn( newRDN );
1091 ldapava_free_dn( newDN );
1097 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
1106 * Parses a relative DN according to flags up to a rdn separator
1107 * or to the end of str.
1108 * Returns the rdn and a pointer to the string continuation, which
1109 * corresponds to the rdn separator or to '\0' in case the string is over.
1112 ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
1116 int rc = LDAP_INVALID_DN_SYNTAX;
1117 int attrTypeEncoding = LDAP_AVA_STRING,
1118 attrValueEncoding = LDAP_AVA_STRING;
1120 struct berval *attrType = NULL;
1121 struct berval *attrValue = NULL;
1123 LDAPRDN *newRDN = NULL;
1129 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );
1134 switch ( LDAP_DN_FORMAT( flags ) ) {
1135 case LDAP_DN_FORMAT_LDAP:
1136 case LDAP_DN_FORMAT_LDAPV3:
1137 case LDAP_DN_FORMAT_LDAPV2:
1138 case LDAP_DN_FORMAT_DCE:
1141 /* unsupported in str2dn */
1142 case LDAP_DN_FORMAT_UFN:
1143 case LDAP_DN_FORMAT_AD_CANONICAL:
1144 return( LDAP_INVALID_DN_SYNTAX );
1147 return( LDAP_OTHER );
1150 if ( str[ 0 ] == '\0' ) {
1151 return( LDAP_SUCCESS );
1155 for ( ; p[ 0 ] || state == GOTAVA; ) {
1158 * The parser in principle advances one token a time,
1159 * or toggles state if preferable.
1164 * an AttributeType can be encoded as:
1165 * - its string representation; in detail, implementations
1166 * MUST recognize AttributeType string type names listed
1167 * in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
1168 * MAY recognize other names.
1169 * - its numeric OID (a dotted decimal string); in detail
1170 * RFC 2253 asserts that ``Implementations MUST allow
1171 * an oid in the attribute type to be prefixed by one
1172 * of the character strings "oid." or "OID."''. As soon
1173 * as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253
1174 * I'm not sure whether this is required or not any
1175 * longer; to be liberal, we still implement it.
1178 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1179 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
1186 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1187 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1192 /* whitespace is allowed (and trimmed) */
1194 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1199 /* error: we expected an AVA */
1205 if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
1206 state = B4OIDATTRTYPE;
1210 /* else must be alpha */
1211 if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
1215 /* LDAPv2 "oid." prefix */
1216 if ( LDAP_DN_LDAPV2( flags ) ) {
1218 * to be overly pedantic, we only accept
1221 if ( flags & LDAP_DN_PEDANTIC ) {
1222 if ( !strncmp( p, "OID.", 4 )
1223 || !strncmp( p, "oid.", 4 ) ) {
1225 state = B4OIDATTRTYPE;
1229 if ( !strncasecmp( p, "oid.", 4 ) ) {
1231 state = B4OIDATTRTYPE;
1237 state = B4STRINGATTRTYPE;
1240 case B4OIDATTRTYPE: {
1241 int err = LDAP_SUCCESS;
1244 type = parse_numericoid( &p, &err, 0 );
1245 if ( type == NULL ) {
1248 attrType = LDAP_MALLOC( sizeof( struct berval ) );
1249 if ( attrType== NULL ) {
1250 rc = LDAP_NO_MEMORY;
1253 attrType->bv_val = type;
1254 attrType->bv_len = strlen( type );
1255 attrTypeEncoding = LDAP_AVA_BINARY;
1257 state = B4AVAEQUALS;
1261 case B4STRINGATTRTYPE: {
1262 const char *startPos, *endPos = NULL;
1266 * the starting char has been found to be
1267 * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
1268 * FIXME: DCE attr types seem to have a more
1269 * restrictive syntax (no '-' ...)
1271 for ( startPos = p++; p[ 0 ]; p++ ) {
1272 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
1276 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
1279 * RFC 2253 does not explicitly
1280 * allow lang extensions to attribute
1283 if ( flags & LDAP_DN_PEDANTIC ) {
1288 * we trim ';' and following lang
1289 * and so from attribute types
1292 for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
1293 || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
1301 len = ( endPos ? endPos : p ) - startPos;
1306 assert( attrType == NULL );
1307 attrType = LDAP_MALLOC( sizeof( struct berval ) );
1308 if ( attrType == NULL ) {
1309 rc = LDAP_NO_MEMORY;
1312 attrType->bv_val = LDAP_STRNDUP( startPos, len );
1313 if ( attrType->bv_val == NULL ) {
1314 rc = LDAP_NO_MEMORY;
1317 attrType->bv_len = len;
1318 attrTypeEncoding = LDAP_AVA_STRING;
1321 * here we need to decide whether to use it as is
1322 * or turn it in OID form; as a consequence, we
1323 * need to decide whether to binary encode the value
1326 state = B4AVAEQUALS;
1331 /* spaces may not be allowed */
1332 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1333 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1338 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1343 /* need equal sign */
1344 if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1349 /* spaces may not be allowed */
1350 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1351 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1356 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1362 * octothorpe means a BER encoded value will follow
1363 * FIXME: I don't think DCE will allow it
1365 if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1367 attrValueEncoding = LDAP_AVA_BINARY;
1368 state = B4BINARYVALUE;
1372 /* STRING value expected */
1375 * if we're pedantic, an attribute type in OID form
1376 * SHOULD imply a BER encoded attribute value; we
1377 * should at least issue a warning
1379 if ( ( flags & LDAP_DN_PEDANTIC )
1380 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1381 /* OID attrType SHOULD use binary encoding */
1385 attrValueEncoding = LDAP_AVA_STRING;
1388 * LDAPv2 allows the attribute value to be quoted;
1389 * also, IA5 values are expected, in principle
1391 if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1392 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1394 state = B4IA5VALUEQUOTED;
1398 if ( LDAP_DN_LDAPV2( flags ) ) {
1405 * here STRING means RFC 2253 string
1406 * FIXME: what about DCE strings?
1408 state = B4STRINGVALUE;
1412 if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
1420 switch ( LDAP_DN_FORMAT( flags ) ) {
1421 case LDAP_DN_FORMAT_LDAP:
1422 case LDAP_DN_FORMAT_LDAPV3:
1423 if ( str2strval( p, &attrValue, &p, flags,
1424 &attrValueEncoding ) ) {
1429 case LDAP_DN_FORMAT_DCE:
1430 if ( DCE2strval( p, &attrValue, &p, flags ) ) {
1443 if ( IA52strval( p, &attrValue, &p, flags ) ) {
1450 case B4IA5VALUEQUOTED:
1452 /* lead quote already stripped */
1453 if ( quotedIA52strval( p, &attrValue,
1467 * we accept empty values
1469 ava = ldapava_new( attrType, attrValue,
1470 attrValueEncoding );
1471 if ( ava == NULL ) {
1472 rc = LDAP_NO_MEMORY;
1476 rdn = ldapava_append_to_rdn( newRDN, ava );
1477 if ( rdn == NULL ) {
1478 rc = LDAP_NO_MEMORY;
1484 * if we got an AVA separator ('+', or ',' for DCE )
1485 * we expect a new AVA for this RDN; otherwise
1486 * we add the RDN to the DN
1488 switch ( LDAP_DN_FORMAT( flags ) ) {
1489 case LDAP_DN_FORMAT_LDAP:
1490 case LDAP_DN_FORMAT_LDAPV3:
1491 case LDAP_DN_FORMAT_LDAPV2:
1492 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1497 case LDAP_DN_FORMAT_DCE:
1498 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1506 * the RDN is over, phew
1513 /* they should have been used in an AVA */
1529 /* They are set to NULL after they're used in an AVA */
1531 ber_bvfree( attrType );
1535 ber_bvfree( attrValue );
1539 ldapava_free_rdn( newRDN );
1545 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n",
1553 * reads in a UTF-8 string value, unescaping stuff:
1554 * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1555 * '\' + HEXPAIR(p) -> unhex(p)
1558 str2strval( const char *str, struct berval **val, const char **next, unsigned flags, unsigned *retFlags )
1560 const char *p, *startPos, *endPos = NULL;
1561 ber_len_t len, escapes, unescapes;
1570 for ( startPos = p = str, escapes = 0, unescapes = 0; p[ 0 ]; p++ ) {
1571 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1573 if ( p[ 0 ] == '\0' ) {
1576 if ( ( p == startPos + 1 && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1577 || ( LDAP_DN_VALUE_END( p[ 1 ] ) && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
1578 || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1583 if ( LDAP_DN_HEXPAIR( p ) ) {
1586 hexstr2bin( p, &c );
1589 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1592 * we assume the string is UTF-8
1594 *retFlags = LDAP_AVA_NONPRINTABLE;
1601 if ( LDAP_DN_PEDANTIC & flags ) {
1605 * FIXME: we allow escaping
1606 * of chars that don't need
1607 * to and do not belong to
1608 * HEXDIGITS (we also allow
1609 * single hexdigit; maybe we
1614 } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) )
1615 || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1618 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1620 * FIXME: maybe we can add
1621 * escapes if not pedantic?
1628 * we do allow unescaped spaces at the end
1629 * of the value only in non-pedantic mode
1631 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1632 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1633 if ( flags & LDAP_DN_PEDANTIC ) {
1637 /* strip trailing (unescaped) spaces */
1638 for ( endPos = p - 1;
1639 endPos > startPos + 1 &&
1640 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1641 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1648 * FIXME: test memory?
1650 len = ( endPos ? endPos : p ) - startPos - escapes - unescapes;
1651 *val = LDAP_MALLOC( sizeof( struct berval ) );
1652 ( *val )->bv_len = len;
1654 if ( escapes == 0 && unescapes == 0 ) {
1655 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1660 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1661 for ( s = 0, d = 0; d < len; ) {
1662 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1664 if ( ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( startPos[ s ] ) )
1665 || ( s == len - 1 && LDAP_DN_NEEDESCAPE_TRAIL( startPos[ s ] ) )
1666 || LDAP_DN_NEEDESCAPE( startPos[ s ] ) ) {
1667 ( *val )->bv_val[ d++ ] =
1670 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1673 hexstr2bin( &startPos[ s ], &c );
1674 ( *val )->bv_val[ d++ ] = c;
1679 * we allow escaping of chars
1680 * that do not need to
1682 ( *val )->bv_val[ d++ ] =
1687 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1691 ( *val )->bv_val[ d ] = '\0';
1692 assert( strlen( ( *val )->bv_val ) == len );
1702 DCE2strval( const char *str, struct berval **val, const char **next, unsigned flags )
1704 const char *p, *startPos, *endPos = NULL;
1705 ber_len_t len, escapes;
1714 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1715 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1717 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1724 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1729 * FIXME: can we accept anything else? I guess we need
1730 * to stop if a value is not legal
1735 * (unescaped) trailing spaces are trimmed must be silently ignored;
1738 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1739 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1740 if ( flags & LDAP_DN_PEDANTIC ) {
1744 /* strip trailing (unescaped) spaces */
1745 for ( endPos = p - 1;
1746 endPos > startPos + 1 &&
1747 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1748 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1755 len = ( endPos ? endPos : p ) - startPos - escapes;
1756 *val = LDAP_MALLOC( sizeof( struct berval ) );
1757 ( *val )->bv_len = len;
1758 if ( escapes == 0 ){
1759 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1764 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1765 for ( s = 0, d = 0; d < len; ) {
1767 * This point is reached only if escapes
1768 * are properly used, so all we need to
1771 if ( LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1775 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1777 ( *val )->bv_val[ d ] = '\0';
1778 assert( strlen( ( *val )->bv_val ) == len );
1787 IA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1789 const char *p, *startPos, *endPos = NULL;
1790 ber_len_t len, escapes;
1803 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1804 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1806 if ( p[ 0 ] == '\0' ) {
1810 if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1811 && ( LDAP_DN_PEDANTIC & flags ) ) {
1816 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1821 * FIXME: can we accept anything else? I guess we need
1822 * to stop if a value is not legal
1826 /* strip trailing (unescaped) spaces */
1828 endPos > startPos + 1 &&
1829 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1830 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1835 *val = LDAP_MALLOC( sizeof( struct berval ) );
1836 len = ( endPos ? endPos : p ) - startPos - escapes;
1837 ( *val )->bv_len = len;
1838 if ( escapes == 0 ) {
1839 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1844 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1845 for ( s = 0, d = 0; d < len; ) {
1846 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1849 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1851 ( *val )->bv_val[ d ] = '\0';
1852 assert( strlen( ( *val )->bv_val ) == len );
1860 quotedIA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1862 const char *p, *startPos, *endPos = NULL;
1864 unsigned escapes = 0;
1873 /* initial quote already eaten */
1874 for ( startPos = p = str; p[ 0 ]; p++ ) {
1876 * According to RFC 1779, the quoted value can
1877 * contain escaped as well as unescaped special values;
1878 * as a consequence we tolerate escaped values
1879 * (e.g. '"\,"' -> '\,') and escape unescaped specials
1880 * (e.g. '","' -> '\,').
1882 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1883 if ( p[ 1 ] == '\0' ) {
1888 if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1889 && ( LDAP_DN_PEDANTIC & flags ) ) {
1891 * do we allow to escape normal chars?
1892 * LDAPv2 does not allow any mechanism
1893 * for escaping chars with '\' and hex
1900 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1902 /* eat closing quotes */
1908 * FIXME: can we accept anything else? I guess we need
1909 * to stop if a value is not legal
1913 if ( endPos == NULL ) {
1917 /* Strip trailing (unescaped) spaces */
1918 for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1922 len = endPos - startPos - escapes;
1924 *val = LDAP_MALLOC( sizeof( struct berval ) );
1925 ( *val )->bv_len = len;
1926 if ( escapes == 0 ) {
1927 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1932 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1933 ( *val )->bv_len = len;
1935 for ( s = d = 0; d < len; ) {
1936 if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1939 ( *val )->bv_val[ d++ ] = str[ s++ ];
1941 ( *val )->bv_val[ d ] = '\0';
1942 assert( strlen( ( *val )->bv_val ) == len );
1951 hexstr2bin( const char *str, char *c )
1961 if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1967 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) ) {
1974 if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1980 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) ) {
1981 *c += c2 - 'a' + 10;
1989 hexstr2binval( const char *str, struct berval **val, const char **next, unsigned flags )
1991 const char *p, *startPos, *endPos = NULL;
2002 for ( startPos = p = str; p[ 0 ]; p += 2 ) {
2003 switch ( LDAP_DN_FORMAT( flags ) ) {
2004 case LDAP_DN_FORMAT_LDAPV3:
2005 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
2010 case LDAP_DN_FORMAT_LDAP:
2011 case LDAP_DN_FORMAT_LDAPV2:
2012 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
2017 case LDAP_DN_FORMAT_DCE:
2018 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
2024 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
2025 if ( flags & LDAP_DN_PEDANTIC ) {
2030 for ( ; p[ 0 ]; p++ ) {
2031 switch ( LDAP_DN_FORMAT( flags ) ) {
2032 case LDAP_DN_FORMAT_LDAPV3:
2033 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
2038 case LDAP_DN_FORMAT_LDAP:
2039 case LDAP_DN_FORMAT_LDAPV2:
2040 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
2045 case LDAP_DN_FORMAT_DCE:
2046 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
2055 if ( !LDAP_DN_HEXPAIR( p ) ) {
2062 len = ( ( endPos ? endPos : p ) - startPos ) / 2;
2064 assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
2066 *val = LDAP_MALLOC( sizeof( struct berval ) );
2067 if ( *val == NULL ) {
2068 return( LDAP_NO_MEMORY );
2071 ( *val )->bv_len = len;
2072 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
2073 if ( ( *val )->bv_val == NULL ) {
2075 return( LDAP_NO_MEMORY );
2078 for ( s = 0, d = 0; d < len; s += 2, d++ ) {
2081 hexstr2bin( &startPos[ s ], &c );
2083 ( *val )->bv_val[ d ] = c;
2086 ( *val )->bv_val[ d ] = '\0';
2093 * convert a byte in a hexadecimal pair
2096 byte2hexpair( const char *val, char *pair )
2098 static const char hexdig[] = "0123456789abcdef";
2104 * we assume the string has enough room for the hex encoding
2108 pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
2109 pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
2115 * convert a binary value in hexadecimal pairs
2118 binval2hexstr( struct berval *val, char *str )
2125 if ( val->bv_len == 0 ) {
2130 * we assume the string has enough room for the hex encoding
2134 for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
2135 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2142 * Length of the string representation, accounting for escaped hex
2146 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
2148 ber_len_t l, cl = 1;
2155 if ( val->bv_len == 0 ) {
2159 for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
2160 cl = ldap_utf8_charlen( p );
2162 /* illegal utf-8 char! */
2165 } else if ( cl > 1 ) {
2168 for ( cnt = 1; cnt < cl; cnt++ ) {
2169 if ( ( p[ cnt ] & 0x80 ) == 0x00 ) {
2173 /* need to escape it */
2177 * there might be some chars we want to escape in form
2178 * of a couple of hexdigits for optimization purposes
2180 } else if ( LDAP_DN_WILLESCAPE( flags, p[ 0 ] ) ) {
2183 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2184 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2185 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2199 * convert to string representation, escaping with hex the UTF-8 stuff;
2200 * assume the destination has enough room for escaping
2203 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2205 ber_len_t s, d, end;
2211 if ( val->bv_len == 0 ) {
2217 * we assume the string has enough room for the hex encoding
2220 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2221 ber_len_t cl = ldap_utf8_charlen( &val->bv_val[ s ] );
2224 * there might be some chars we want to escape in form
2225 * of a couple of hexdigits for optimization purposes
2227 if ( cl > 1 || LDAP_DN_WILLESCAPE( flags, val->bv_val[ s ] ) ) {
2230 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2236 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2237 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2238 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2241 str[ d++ ] = val->bv_val[ s++ ];
2251 * Length of the IA5 string representation (no UTF-8 allowed)
2254 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
2263 if ( val->bv_len == 0 ) {
2267 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2269 * Turn value into a binary encoded BER
2274 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2275 if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2276 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2277 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2292 * convert to string representation (np UTF-8)
2293 * assume the destination has enough room for escaping
2296 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2298 ber_len_t s, d, end;
2304 if ( val->bv_len == 0 ) {
2309 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2311 * Turn value into a binary encoded BER
2318 * we assume the string has enough room for the hex encoding
2322 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2323 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2324 || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2325 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2328 str[ d++ ] = val->bv_val[ s++ ];
2338 * Length of the (supposedly) DCE string representation,
2339 * accounting for escaped hex of UTF-8 chars
2342 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2351 if ( val->bv_len == 0 ) {
2355 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2357 * FIXME: Turn the value into a binary encoded BER?
2362 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2363 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2378 * convert to (supposedly) DCE string representation,
2379 * escaping with hex the UTF-8 stuff;
2380 * assume the destination has enough room for escaping
2383 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2391 if ( val->bv_len == 0 ) {
2396 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2398 * FIXME: Turn the value into a binary encoded BER?
2406 * we assume the string has enough room for the hex encoding
2410 for ( s = 0, d = 0; s < val->bv_len; ) {
2411 if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2414 str[ d++ ] = val->bv_val[ s++ ];
2424 * Length of the (supposedly) AD canonical string representation,
2425 * accounting for escaped hex of UTF-8 chars
2428 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2437 if ( val->bv_len == 0 ) {
2441 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2443 * FIXME: Turn the value into a binary encoded BER?
2448 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2449 if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2464 * convert to (supposedly) AD string representation,
2465 * escaping with hex the UTF-8 stuff;
2466 * assume the destination has enough room for escaping
2469 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2477 if ( val->bv_len == 0 ) {
2482 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2484 * FIXME: Turn the value into a binary encoded BER?
2492 * we assume the string has enough room for the hex encoding
2496 for ( s = 0, d = 0; s < val->bv_len; ) {
2497 if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2500 str[ d++ ] = val->bv_val[ s++ ];
2510 * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2511 * the forst part of the AD representation of the DN is written in DNS
2512 * form, i.e. dot separated domain name components (as suggested
2513 * by Luke Howard, http://www.padl.com/~lukeh)
2516 dn2domain( LDAPDN *dn, char *str, int *iRDN )
2519 int domain = 0, first = 1;
2520 ber_len_t l = 1; /* we move the null also */
2522 /* we are guaranteed there's enough memory in str */
2528 assert( *iRDN > 0 );
2530 for ( i = *iRDN; i >= 0; i-- ) {
2534 assert( dn[ i ][ 0 ] );
2537 assert( rdn[ 0 ][ 0 ] );
2538 ava = rdn[ 0 ][ 0 ];
2540 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2548 AC_MEMCPY( str, ava->la_value->bv_val,
2549 ava->la_value->bv_len + 1);
2550 l += ava->la_value->bv_len;
2553 AC_MEMCPY( str + ava->la_value->bv_len + 1, str, l);
2554 AC_MEMCPY( str, ava->la_value->bv_val,
2555 ava->la_value->bv_len );
2556 str[ ava->la_value->bv_len ] = '.';
2557 l += ava->la_value->bv_len + 1;
2567 rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
2568 int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2575 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2576 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2578 /* len(type) + '=' + '+' | ',' */
2579 l += ava->la_attr->bv_len + 2;
2581 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2582 /* octothorpe + twice the length */
2583 l += 1 + 2 * ava->la_value->bv_len;
2587 unsigned f = flags | ava->la_flags;
2589 if ( ( *s2l )( ava->la_value, f, &vl ) ) {
2602 rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
2603 int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2608 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2609 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2611 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2612 ava->la_attr->bv_len );
2613 l += ava->la_attr->bv_len;
2617 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2619 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2622 l += 2 * ava->la_value->bv_len;
2626 unsigned f = flags | ava->la_flags;
2628 if ( ( *s2s )( ava->la_value, &str[ l ], f, &vl ) ) {
2633 str[ l++ ] = ( rdn[ iAVA + 1 ] ? '+' : ',' );
2642 rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2649 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2650 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2652 /* len(type) + '=' + ',' | '/' */
2653 l += ava->la_attr->bv_len + 2;
2655 switch ( ava->la_flags ) {
2656 case LDAP_AVA_BINARY:
2657 /* octothorpe + twice the length */
2658 l += 1 + 2 * ava->la_value->bv_len;
2661 case LDAP_AVA_STRING: {
2663 unsigned f = flags | ava->la_flags;
2665 if ( strval2DCEstrlen( ava->la_value, f, &vl ) ) {
2683 rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2688 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2689 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2694 str[ l++ ] = ( iAVA ? ',' : '/' );
2697 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2698 ava->la_attr->bv_len );
2699 l += ava->la_attr->bv_len;
2703 switch ( ava->la_flags ) {
2704 case LDAP_AVA_BINARY:
2706 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2709 l += 2 * ava->la_value->bv_len;
2712 case LDAP_AVA_STRING: {
2714 unsigned f = flags | ava->la_flags;
2716 if ( strval2DCEstr( ava->la_value, &str[ l ], f, &vl ) ) {
2734 rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2744 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2745 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2748 l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
2750 /* FIXME: are binary values allowed in UFN? */
2751 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2752 /* octothorpe + twice the value */
2753 l += 1 + 2 * ava->la_value->bv_len;
2757 unsigned f = flags | ava->la_flags;
2759 if ( strval2strlen( ava->la_value, f, &vl ) ) {
2772 rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
2777 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2778 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2780 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2782 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2785 l += 2 * ava->la_value->bv_len;
2789 unsigned f = flags | ava->la_flags;
2791 if ( strval2str( ava->la_value, &str[ l ], f, &vl ) ) {
2797 if ( rdn[ iAVA + 1 ]) {
2798 AC_MEMCPY( &str[ l ], " + ", 3 );
2802 AC_MEMCPY( &str[ l ], ", ", 2 );
2813 rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2823 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2824 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2829 /* FIXME: are binary values allowed in UFN? */
2830 switch ( ava->la_flags ) {
2831 case LDAP_AVA_BINARY:
2832 /* octothorpe + twice the value */
2833 l += 1 + 2 * ava->la_value->bv_len;
2836 case LDAP_AVA_STRING: {
2838 unsigned f = flags | ava->la_flags;
2840 if ( strval2ADstrlen( ava->la_value, f, &vl ) ) {
2858 rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2863 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2864 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2869 str[ l++ ] = ( iAVA ? ',' : '/' );
2872 switch ( ava->la_flags ) {
2873 case LDAP_AVA_BINARY:
2875 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2878 l += 2 * ava->la_value->bv_len;
2881 case LDAP_AVA_STRING: {
2883 unsigned f = flags | ava->la_flags;
2885 if ( strval2ADstr( ava->la_value, &str[ l ], f, &vl ) ) {
2905 * Returns in str a string representation of rdn based on flags.
2906 * There is some duplication of code between this and ldap_dn2str;
2907 * this is wanted to reduce the allocation of temporary buffers.
2910 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2917 if ( rdn == NULL ) {
2918 *str = LDAP_STRDUP( "" );
2919 return( LDAP_SUCCESS );
2923 * This routine wastes "back" bytes at the end of the string
2927 switch ( LDAP_DN_FORMAT( flags ) ) {
2928 case LDAP_DN_FORMAT_LDAPV3:
2929 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2930 return( LDAP_OTHER );
2934 case LDAP_DN_FORMAT_LDAPV2:
2935 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2936 return( LDAP_OTHER );
2940 case LDAP_DN_FORMAT_UFN:
2941 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2942 return( LDAP_OTHER );
2946 case LDAP_DN_FORMAT_DCE:
2947 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2948 return( LDAP_OTHER );
2952 case LDAP_DN_FORMAT_AD_CANONICAL:
2953 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2954 return( LDAP_OTHER );
2959 return( LDAP_INVALID_DN_SYNTAX );
2962 *str = LDAP_MALLOC( l + 1 );
2964 switch ( LDAP_DN_FORMAT( flags ) ) {
2965 case LDAP_DN_FORMAT_LDAPV3:
2966 rc = rdn2str( rdn, *str, flags, &l, strval2str );
2970 case LDAP_DN_FORMAT_LDAPV2:
2971 rc = rdn2str( rdn, *str, flags, &l, strval2IA5str );
2975 case LDAP_DN_FORMAT_UFN:
2976 rc = rdn2UFNstr( rdn, *str, flags, &l );
2980 case LDAP_DN_FORMAT_DCE:
2981 rc = rdn2DCEstr( rdn, *str, flags, &l, 1 );
2985 case LDAP_DN_FORMAT_AD_CANONICAL:
2986 rc = rdn2ADstr( rdn, *str, flags, &l, 1 );
2991 /* need at least one of the previous */
2992 return( LDAP_OTHER );
2996 ldap_memfree( *str );
2997 return( LDAP_OTHER );
3000 ( *str )[ l - back ] = '\0';
3002 return( LDAP_SUCCESS );
3006 * Very bulk implementation; many optimizations can be performed
3007 * - a NULL dn results in an empty string ""
3010 * a) what do we do if a UTF-8 string must be converted in LDAPv2?
3011 * we must encode it in binary form ('#' + HEXPAIRs)
3012 * b) does DCE/AD support UTF-8?
3013 * no clue; don't think so.
3014 * c) what do we do when binary values must be converted in UTF/DCE/AD?
3015 * use binary encoded BER
3017 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
3020 int rc = LDAP_OTHER;
3023 /* stringifying helpers for LDAPv3/LDAPv2 */
3024 int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
3025 int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
3029 Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2str(%u)\n%s%s", flags, "", "" );
3034 * a null dn means an empty dn string
3035 * FIXME: better raise an error?
3038 *str = LDAP_STRDUP( "" );
3039 return( LDAP_SUCCESS );
3042 switch ( LDAP_DN_FORMAT( flags ) ) {
3043 case LDAP_DN_FORMAT_LDAPV3:
3044 sv2l = strval2strlen;
3048 case LDAP_DN_FORMAT_LDAPV2:
3049 sv2l = strval2IA5strlen;
3050 sv2s = strval2IA5str;
3053 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3055 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3057 if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
3058 goto return_results;
3064 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3065 rc = LDAP_NO_MEMORY;
3069 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
3071 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3073 if ( rdn2str( rdn, &( *str )[ l ], flags,
3077 goto return_results;
3085 * trim the last ',' (the allocated memory
3086 * is one byte longer than required)
3088 ( *str )[ len - 1 ] = '\0';
3093 case LDAP_DN_FORMAT_UFN: {
3096 * FIXME: quoting from RFC 1781:
3098 To take a distinguished name, and generate a name of this format with
3099 attribute types omitted, the following steps are followed.
3101 1. If the first attribute is of type CommonName, the type may be
3104 2. If the last attribute is of type Country, the type may be
3107 3. If the last attribute is of type Country, the last
3108 Organisation attribute may have the type omitted.
3110 4. All attributes of type OrganisationalUnit may have the type
3111 omitted, unless they are after an Organisation attribute or
3112 the first attribute is of type OrganisationalUnit.
3114 * this should be the pedantic implementation.
3116 * Here the standard implementation reflects
3117 * the one historically provided by OpenLDAP
3118 * (and UMIch, I presume), with the variant
3119 * of spaces and plusses (' + ') separating
3122 * A non-standard but nice implementation could
3123 * be to turn the final "dc" attributes into a
3124 * dot-separated domain.
3126 * Other improvements could involve the use of
3127 * friendly country names and so.
3130 int leftmost_dc = -1;
3132 #endif /* DC_IN_UFN */
3134 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3136 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3138 if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
3139 goto return_results;
3144 if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
3145 if ( leftmost_dc == -1 ) {
3151 #endif /* DC_IN_UFN */
3154 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3155 rc = LDAP_NO_MEMORY;
3160 if ( leftmost_dc == -1 ) {
3161 #endif /* DC_IN_UFN */
3162 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
3164 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3166 if ( rdn2UFNstr( rdn, &( *str )[ l ],
3170 goto return_results;
3176 * trim the last ', ' (the allocated memory
3177 * is two bytes longer than required)
3179 ( *str )[ len - 2 ] = '\0';
3182 last_iRDN = iRDN - 1;
3184 for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
3186 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3188 if ( rdn2UFNstr( rdn, &( *str )[ l ],
3192 goto return_results;
3197 if ( !dn2domain( dn, &( *str )[ l ], &last_iRDN ) ) {
3200 goto return_results;
3203 /* the string is correctly terminated by dn2domain */
3205 #endif /* DC_IN_UFN */
3211 case LDAP_DN_FORMAT_DCE:
3213 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3215 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3217 if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
3218 goto return_results;
3224 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3225 rc = LDAP_NO_MEMORY;
3229 for ( l = 0; iRDN--; ) {
3231 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3233 if ( rdn2DCEstr( rdn, &( *str )[ l ], flags,
3237 goto return_results;
3244 ( *str )[ len ] = '\0';
3249 case LDAP_DN_FORMAT_AD_CANONICAL: {
3252 * Sort of UFN for DCE DNs: a slash ('/') separated
3253 * global->local DN with no types; strictly speaking,
3254 * the naming context should be a domain, which is
3255 * written in DNS-style, e.g. dot-deparated.
3259 * "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3263 * "microsoft.com/People/Bill,Gates"
3265 for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
3267 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3269 if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
3270 goto return_results;
3276 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3277 rc = LDAP_NO_MEMORY;
3282 if ( iRDN && dn2domain( dn, *str, &iRDN ) ) {
3283 for ( l = strlen( *str ); iRDN >= 0 ; iRDN-- ) {
3285 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3287 if ( rdn2ADstr( rdn, &( *str )[ l ],
3288 flags, &rdnl, 0 ) ) {
3291 goto return_results;
3300 * Strictly speaking, AD canonical requires
3301 * a DN to be in the form "..., dc=smtg",
3302 * i.e. terminated by a domain component
3304 if ( flags & LDAP_DN_PEDANTIC ) {
3307 rc = LDAP_INVALID_DN_SYNTAX;
3311 for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3313 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3315 if ( rdn2ADstr( rdn, &( *str )[ l ],
3316 flags, &rdnl, first ) ) {
3319 goto return_results;
3328 ( *str )[ len ] = '\0';
3335 return( LDAP_INVALID_DN_SYNTAX );
3339 Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2str(%s,%u)=%d\n", *str, flags, rc );