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_LDAP, 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_LDAP )
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_LDAP )
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_LDAP, 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_LDAP, 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_LDAP (rfc 2253 and ldapbis liberal,
546 * plus some rfc 1779)
547 * LDAP_DN_FORMAT_LDAPV3 (rfc 2253 and ldapbis)
548 * LDAP_DN_FORMAT_LDAPV2 (rfc 1779)
549 * LDAP_DN_FORMAT_DCE (?)
551 * fout can be any of the above except
552 * LDAP_DN_FORMAT_LDAP
554 * LDAP_DN_FORMAT_UFN (rfc 1781, partial and with extensions)
555 * LDAP_DN_FORMAT_AD_CANONICAL (?)
558 dn2dn( const char *dnin, unsigned fin, unsigned fout )
561 LDAPDN *tmpDN = NULL;
567 if ( ldap_str2dn( dnin , &tmpDN, fin ) != LDAP_SUCCESS ) {
571 /* don't care about the result ... */
572 ldap_dn2str( tmpDN, &dnout, fout );
574 ldapava_free_dn( tmpDN );
582 /* #define B4ATTRTYPE 0x0001 */
583 #define B4OIDATTRTYPE 0x0002
584 #define B4STRINGATTRTYPE 0x0003
586 #define B4AVAEQUALS 0x0100
587 #define B4AVASEP 0x0200
588 #define B4RDNSEP 0x0300
589 #define GOTAVA 0x0400
591 #define B4ATTRVALUE 0x0010
592 #define B4STRINGVALUE 0x0020
593 #define B4IA5VALUEQUOTED 0x0030
594 #define B4IA5VALUE 0x0040
595 #define B4BINARYVALUE 0x0050
597 /* Helpers (mostly from slapd.h; maybe it should be rewritten from this) */
598 #define LDAP_DN_ASCII_SPACE(c) \
599 ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
600 #define LDAP_DN_ASCII_LOWER(c) ( (c) >= 'a' && (c) <= 'z' )
601 #define LDAP_DN_ASCII_UPPER(c) ( (c) >= 'A' && (c) <= 'Z' )
602 #define LDAP_DN_ASCII_ALPHA(c) \
603 ( LDAP_DN_ASCII_LOWER(c) || LDAP_DN_ASCII_UPPER(c) )
604 #define LDAP_DN_ASCII_DIGIT(c) ( (c) >= '0' && (c) <= '9' )
605 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) ( (c) >= 'a' && (c) <= 'f' )
606 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) ( (c) >= 'A' && (c) <= 'F' )
607 #define LDAP_DN_ASCII_HEXDIGIT(c) \
608 ( LDAP_DN_ASCII_DIGIT(c) \
609 || LDAP_DN_ASCII_LCASE_HEXALPHA(c) \
610 || LDAP_DN_ASCII_UCASE_HEXALPHA(c) )
611 #define LDAP_DN_ASCII_ALNUM(c) \
612 ( LDAP_DN_ASCII_ALPHA(c) || LDAP_DN_ASCII_DIGIT(c) )
613 #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' )
616 #define LDAP_DN_OID_LEADCHAR(c) ( LDAP_DN_ASCII_DIGIT(c) )
617 #define LDAP_DN_DESC_LEADCHAR(c) ( LDAP_DN_ASCII_ALPHA(c) )
618 #define LDAP_DN_DESC_CHAR(c) ( LDAP_DN_ASCII_ALNUM(c) || (c) == '-' )
619 #define LDAP_DN_LANG_SEP(c) ( (c) == ';' )
620 #define LDAP_DN_ATTRDESC_CHAR(c) \
621 ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
623 /* special symbols */
624 #define LDAP_DN_AVA_EQUALS(c) ( (c) == '=' )
625 #define LDAP_DN_AVA_SEP(c) ( (c) == '+' )
626 #define LDAP_DN_RDN_SEP(c) ( (c) == ',' )
627 #define LDAP_DN_RDN_SEP_V2(c) ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
628 #define LDAP_DN_OCTOTHORPE(c) ( (c) == '#' )
629 #define LDAP_DN_QUOTES(c) ( (c) == '\"' )
630 #define LDAP_DN_ESCAPE(c) ( (c) == '\\' )
631 #define LDAP_DN_VALUE_END(c) \
632 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
633 #define LDAP_DN_NE(c) \
634 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
635 || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
636 #define LDAP_DN_NEEDESCAPE(c) \
637 ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
638 #define LDAP_DN_NEEDESCAPE_LEAD(c) \
639 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) )
640 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
641 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
642 #define LDAP_DN_WILLESCAPE_CHAR( c) \
643 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
644 #define LDAP_DN_WILLESCAPE(f, c) \
645 ( ( !( (f) & LDAP_DN_PRETTY ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
648 #define LDAP_DN_VALUE_END_V2(c) \
649 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
651 #define LDAP_DN_V2_SPECIAL(c) \
652 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
653 || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
654 || LDAP_DN_OCTOTHORPE(c) )
655 #define LDAP_DN_V2_PAIR(c) \
656 ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
659 * DCE (mostly from Luke Howard and IBM implementation for AIX)
661 * From: "Application Development Guide - Directory Services" (FIXME: add link?)
662 * Here escapes and valid chars for GDS are considered; as soon as more
663 * specific info is found, the macros will be updated.
665 * Chars: 'a'-'z', 'A'-'Z', '0'-'9',
666 * '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
668 * Metachars: '/', ',', '=', '\'.
670 * the '\' is used to escape other metachars.
676 * Attribute types must start with alphabetic chars and can contain
677 * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
679 #define LDAP_DN_RDN_SEP_DCE(c) ( (c) == '/' )
680 #define LDAP_DN_AVA_SEP_DCE(c) ( (c) == ',' )
681 #define LDAP_DN_ESCAPE_DCE(c) ( LDAP_DN_ESCAPE(c) )
682 #define LDAP_DN_VALUE_END_DCE(c) \
683 ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
684 #define LDAP_DN_NEEDESCAPE_DCE(c) \
685 ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
688 #define LDAP_DN_RDN_SEP_AD(c) ( (c) == '/' )
689 #define LDAP_DN_ESCAPE_AD(c) ( LDAP_DN_ESCAPE(c) )
690 #define LDAP_DN_AVA_SEP_AD(c) ( (c) == ',' ) /* assume same as DCE */
691 #define LDAP_DN_VALUE_END_AD(c) \
692 ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
693 #define LDAP_DN_NEEDESCAPE_AD(c) \
694 ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
697 #define LDAP_DN_HEXPAIR(s) \
698 ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
699 #define LDAP_DC_ATTR "dc"
700 /* better look at the AttributeDescription? */
702 /* FIXME: no composite rdn or non-"dc" types, right?
703 * (what about "dc" in OID form?) */
704 /* FIXME: we do not allow binary values in domain, right? */
705 /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
706 #define LDAP_DN_IS_RDN_DC( rdn ) \
707 ( ( rdn ) && ( rdn )[ 0 ][ 0 ] && !( rdn )[ 1 ] \
708 && ( ( rdn )[ 0 ][ 0 ]->la_flags == LDAP_AVA_STRING ) \
709 && ! strcasecmp( ( rdn )[ 0 ][ 0 ]->la_attr->bv_val, LDAP_DC_ATTR ) )
711 /* Composite rules */
712 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
713 ( LDAP_DN_LDAPV2(f) \
714 || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
715 #define LDAP_DN_ALLOW_SPACES(f) \
716 ( LDAP_DN_LDAPV2(f) \
717 || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
718 #define LDAP_DN_LDAP(f) \
719 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
720 #define LDAP_DN_LDAPV3(f) \
721 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
722 #define LDAP_DN_LDAPV2(f) \
723 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
724 #define LDAP_DN_DCE(f) \
725 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
726 #define LDAP_DN_UFN(f) \
727 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
728 #define LDAP_DN_ADC(f) \
729 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
730 #define LDAP_DN_FORMAT(f) ( (f) & LDAP_DN_FORMAT_MASK )
733 * LDAPAVA helpers (will become part of the API for operations
734 * on structural representations of DNs).
737 ldapava_new( const struct berval *attr, const struct berval *val,
745 ava = LDAP_MALLOC( sizeof( LDAPAVA ) );
747 /* should we test it? */
752 ava->la_attr = ( struct berval * )attr;
753 ava->la_value = ( struct berval * )val;
754 ava->la_flags = flags;
760 ldapava_free( LDAPAVA *ava )
764 ber_bvfree( ava->la_attr );
765 ber_bvfree( ava->la_value );
771 ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava )
779 for ( i = 0U; rdn[ i ]; i++ ) {
783 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
784 newRDN[ i ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
785 newRDN[ i ][ 0 ] = ava;
786 newRDN[ i + 1 ] = NULL;
792 ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where )
800 for ( i = 0U; rdn[ i ]; i++ ) {
806 /* assume "at end", which corresponds to
807 * ldapava_append_to_rdn */
810 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
812 /* data after insert point */
813 AC_MEMCPY( &newRDN[ where + 1 ], &newRDN[ where ],
814 ( i - where ) * sizeof( LDAPRDN * ) );
816 newRDN[ where ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
817 newRDN[ where ][ 0 ] = ava;
818 newRDN[ i + 1 ] = NULL;
824 ldapava_free_rdn( LDAPRDN *rdn )
832 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
833 assert( rdn[ iAVA ][ 0 ] );
835 ldapava_free( rdn[ iAVA ][ 0 ] );
842 ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn )
850 for ( i = 0U; dn[ i ]; i++ ) {
854 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
855 newDN[ i ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
856 newDN[ i ][ 0 ] = rdn;
857 newDN[ i + 1 ] = NULL;
863 ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where )
871 for ( i = 0U; dn[ i ]; i++ ) {
877 /* assume "at end", which corresponds to
878 * ldapava_append_to_dn */
881 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
883 /* data after insert point */
884 AC_MEMCPY( &newDN[ where + 1 ], &newDN[ where ],
885 ( i - where ) * sizeof( LDAPDN * ) );
887 newDN[ where ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
888 newDN[ where ][ 0 ] = rdn;
889 newDN[ i + 1 ] = NULL;
895 ldapava_free_dn( LDAPDN *dn )
903 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
904 assert( dn[ iRDN ][ 0 ] );
906 ldapava_free_rdn( dn[ iRDN ][ 0 ] );
913 * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
914 * into a structural representation of the DN, by separating attribute
915 * types and values encoded in the more appropriate form, which is
916 * string or OID for attribute types and binary form of the BER encoded
917 * value or Unicode string. Formats different from LDAPv3 are parsed
918 * according to their own rules and turned into the more appropriate
919 * form according to LDAPv3.
921 * NOTE: I realize the code is getting spaghettish; it is rather
922 * experimental and will hopefully turn into something more simple
923 * and readable as soon as it works as expected.
927 ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
930 int rc = LDAP_INVALID_DN_SYNTAX;
932 LDAPDN *newDN = NULL;
933 LDAPRDN *newRDN = NULL;
938 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );
942 switch ( LDAP_DN_FORMAT( flags ) ) {
943 case LDAP_DN_FORMAT_LDAP:
944 case LDAP_DN_FORMAT_LDAPV3:
945 case LDAP_DN_FORMAT_LDAPV2:
946 case LDAP_DN_FORMAT_DCE:
949 /* unsupported in str2dn */
950 case LDAP_DN_FORMAT_UFN:
951 case LDAP_DN_FORMAT_AD_CANONICAL:
952 return( LDAP_INVALID_DN_SYNTAX );
955 return( LDAP_OTHER );
958 if ( str[ 0 ] == '\0' ) {
959 return( LDAP_SUCCESS );
963 if ( LDAP_DN_DCE( flags ) ) {
966 * (from Luke Howard: thnx) A RDN separator is required
967 * at the beginning of an (absolute) DN.
969 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
974 } else if ( LDAP_DN_LDAP( flags ) ) {
976 * if dn starts with '/' let's make it a DCE dn
978 if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
979 flags |= LDAP_DN_FORMAT_DCE;
984 for ( ; p[ 0 ]; p++ ) {
987 rc = ldap_str2rdn( p, &newRDN, &p, flags );
988 if ( rc != LDAP_SUCCESS ) {
993 * We expect a rdn separator
996 switch ( LDAP_DN_FORMAT( flags ) ) {
997 case LDAP_DN_FORMAT_LDAPV3:
998 if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
1004 case LDAP_DN_FORMAT_LDAP:
1005 case LDAP_DN_FORMAT_LDAPV2:
1006 if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
1012 case LDAP_DN_FORMAT_DCE:
1013 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
1022 if ( LDAP_DN_DCE( flags ) ) {
1023 /* add in reversed order */
1024 dn = ldapava_insert_into_dn( newDN, newRDN, 0 );
1026 dn = ldapava_append_to_dn( newDN, newRDN );
1030 rc = LDAP_NO_MEMORY;
1037 if ( p[ 0 ] == '\0' ) {
1040 * the DN is over, phew
1049 ldapava_free_rdn( newRDN );
1053 ldapava_free_dn( newDN );
1059 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
1068 * Parses a relative DN according to flags up to a rdn separator
1069 * or to the end of str.
1070 * Returns the rdn and a pointer to the string continuation, which
1071 * corresponds to the rdn separator or to '\0' in case the string is over.
1074 ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
1078 int rc = LDAP_INVALID_DN_SYNTAX;
1079 int attrTypeEncoding = LDAP_AVA_STRING,
1080 attrValueEncoding = LDAP_AVA_STRING;
1082 struct berval *attrType = NULL;
1083 struct berval *attrValue = NULL;
1085 LDAPRDN *newRDN = NULL;
1091 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );
1096 switch ( LDAP_DN_FORMAT( flags ) ) {
1097 case LDAP_DN_FORMAT_LDAP:
1098 case LDAP_DN_FORMAT_LDAPV3:
1099 case LDAP_DN_FORMAT_LDAPV2:
1100 case LDAP_DN_FORMAT_DCE:
1103 /* unsupported in str2dn */
1104 case LDAP_DN_FORMAT_UFN:
1105 case LDAP_DN_FORMAT_AD_CANONICAL:
1106 return( LDAP_INVALID_DN_SYNTAX );
1109 return( LDAP_OTHER );
1112 if ( str[ 0 ] == '\0' ) {
1113 return( LDAP_SUCCESS );
1117 for ( ; p[ 0 ] || state == GOTAVA; ) {
1120 * The parser in principle advances one token a time,
1121 * or toggles state if preferable.
1126 * an AttributeType can be encoded as:
1127 * - its string representation; in detail, implementations
1128 * MUST recognize AttributeType string type names listed
1129 * in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
1130 * MAY recognize other names.
1131 * - its numeric OID (a dotted decimal string); in detail
1132 * RFC 2253 asserts that ``Implementations MUST allow
1133 * an oid in the attribute type to be prefixed by one
1134 * of the character strings "oid." or "OID."''. As soon
1135 * as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253
1136 * I'm not sure whether this is required or not any
1137 * longer; to be liberal, we still implement it.
1140 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1141 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
1148 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1149 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1154 /* whitespace is allowed (and trimmed) */
1156 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1161 /* error: we expected an AVA */
1167 if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
1168 state = B4OIDATTRTYPE;
1172 /* else must be alpha */
1173 if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
1177 /* LDAPv2 "oid." prefix */
1178 if ( LDAP_DN_LDAPV2( flags ) ) {
1180 * to be overly pedantic, we only accept
1183 if ( flags & LDAP_DN_PEDANTIC ) {
1184 if ( !strncmp( p, "OID.", 4 )
1185 || !strncmp( p, "oid.", 4 ) ) {
1187 state = B4OIDATTRTYPE;
1191 if ( !strncasecmp( p, "oid.", 4 ) ) {
1193 state = B4OIDATTRTYPE;
1199 state = B4STRINGATTRTYPE;
1202 case B4OIDATTRTYPE: {
1203 int err = LDAP_SUCCESS;
1206 type = parse_numericoid( &p, &err, 0 );
1207 if ( type == NULL ) {
1210 attrType = LDAP_MALLOC( sizeof( struct berval ) );
1211 if ( attrType== NULL ) {
1212 rc = LDAP_NO_MEMORY;
1215 attrType->bv_val = type;
1216 attrType->bv_len = strlen( type );
1217 attrTypeEncoding = LDAP_AVA_BINARY;
1219 state = B4AVAEQUALS;
1223 case B4STRINGATTRTYPE: {
1224 const char *startPos, *endPos = NULL;
1228 * the starting char has been found to be
1229 * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
1230 * FIXME: DCE attr types seem to have a more
1231 * restrictive syntax (no '-' ...)
1233 for ( startPos = p++; p[ 0 ]; p++ ) {
1234 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
1238 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
1241 * RFC 2253 does not explicitly
1242 * allow lang extensions to attribute
1245 if ( flags & LDAP_DN_PEDANTIC ) {
1250 * we trim ';' and following lang
1251 * and so from attribute types
1254 for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
1255 || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
1263 len = ( endPos ? endPos : p ) - startPos;
1268 assert( attrType == NULL );
1269 attrType = LDAP_MALLOC( sizeof( struct berval ) );
1270 if ( attrType == NULL ) {
1271 rc = LDAP_NO_MEMORY;
1274 attrType->bv_val = LDAP_STRNDUP( startPos, len );
1275 if ( attrType->bv_val == NULL ) {
1276 rc = LDAP_NO_MEMORY;
1279 attrType->bv_len = len;
1280 attrTypeEncoding = LDAP_AVA_STRING;
1283 * here we need to decide whether to use it as is
1284 * or turn it in OID form; as a consequence, we
1285 * need to decide whether to binary encode the value
1288 state = B4AVAEQUALS;
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++ ) {
1305 /* need equal sign */
1306 if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1311 /* spaces may not be allowed */
1312 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1313 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1318 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1324 * octothorpe means a BER encoded value will follow
1325 * FIXME: I don't think DCE will allow it
1327 if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1329 attrValueEncoding = LDAP_AVA_BINARY;
1330 state = B4BINARYVALUE;
1334 /* STRING value expected */
1337 * if we're pedantic, an attribute type in OID form
1338 * SHOULD imply a BER encoded attribute value; we
1339 * should at least issue a warning
1341 if ( ( flags & LDAP_DN_PEDANTIC )
1342 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1343 /* OID attrType SHOULD use binary encoding */
1347 attrValueEncoding = LDAP_AVA_STRING;
1350 * LDAPv2 allows the attribute value to be quoted;
1351 * also, IA5 values are expected, in principle
1353 if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1354 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1356 state = B4IA5VALUEQUOTED;
1360 if ( LDAP_DN_LDAPV2( flags ) ) {
1367 * here STRING means RFC 2253 string
1368 * FIXME: what about DCE strings?
1370 state = B4STRINGVALUE;
1374 if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
1382 switch ( LDAP_DN_FORMAT( flags ) ) {
1383 case LDAP_DN_FORMAT_LDAP:
1384 case LDAP_DN_FORMAT_LDAPV3:
1385 if ( str2strval( p, &attrValue, &p, flags,
1386 &attrValueEncoding ) ) {
1391 case LDAP_DN_FORMAT_DCE:
1392 if ( DCE2strval( p, &attrValue, &p, flags ) ) {
1405 if ( IA52strval( p, &attrValue, &p, flags ) ) {
1412 case B4IA5VALUEQUOTED:
1414 /* lead quote already stripped */
1415 if ( quotedIA52strval( p, &attrValue,
1429 * we accept empty values
1431 ava = ldapava_new( attrType, attrValue,
1432 attrValueEncoding );
1433 if ( ava == NULL ) {
1434 rc = LDAP_NO_MEMORY;
1438 rdn = ldapava_append_to_rdn( newRDN, ava );
1439 if ( rdn == NULL ) {
1440 rc = LDAP_NO_MEMORY;
1446 * if we got an AVA separator ('+', or ',' for DCE )
1447 * we expect a new AVA for this RDN; otherwise
1448 * we add the RDN to the DN
1450 switch ( LDAP_DN_FORMAT( flags ) ) {
1451 case LDAP_DN_FORMAT_LDAP:
1452 case LDAP_DN_FORMAT_LDAPV3:
1453 case LDAP_DN_FORMAT_LDAPV2:
1454 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1459 case LDAP_DN_FORMAT_DCE:
1460 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1468 * the RDN is over, phew
1475 /* they should have been used in an AVA */
1491 /* They are set to NULL after they're used in an AVA */
1493 ber_bvfree( attrType );
1497 ber_bvfree( attrValue );
1501 ldapava_free_rdn( newRDN );
1507 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n",
1515 * reads in a UTF-8 string value, unescaping stuff:
1516 * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1517 * '\' + HEXPAIR(p) -> unhex(p)
1520 str2strval( const char *str, struct berval **val, const char **next, unsigned flags, unsigned *retFlags )
1522 const char *p, *startPos, *endPos = NULL;
1523 ber_len_t len, escapes, unescapes;
1532 for ( startPos = p = str, escapes = 0, unescapes = 0; p[ 0 ]; p++ ) {
1533 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1535 if ( p[ 0 ] == '\0' ) {
1538 if ( ( p == startPos + 1 && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1539 || ( LDAP_DN_VALUE_END( p[ 1 ] ) && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
1540 || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1545 if ( LDAP_DN_HEXPAIR( p ) ) {
1548 hexstr2bin( p, &c );
1551 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1554 * we assume the string is UTF-8
1556 *retFlags = LDAP_AVA_NONPRINTABLE;
1563 if ( LDAP_DN_PEDANTIC & flags ) {
1567 * FIXME: we allow escaping
1568 * of chars that don't need
1569 * to and do not belong to
1570 * HEXDIGITS (we also allow
1571 * single hexdigit; maybe we
1576 } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) )
1577 || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1580 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1582 * FIXME: maybe we can add
1583 * escapes if not pedantic?
1590 * we do allow unescaped spaces at the end
1591 * of the value only in non-pedantic mode
1593 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1594 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1595 if ( flags & LDAP_DN_PEDANTIC ) {
1599 /* strip trailing (unescaped) spaces */
1600 for ( endPos = p - 1;
1601 endPos > startPos + 1 &&
1602 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1603 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1610 * FIXME: test memory?
1612 len = ( endPos ? endPos : p ) - startPos - escapes - unescapes;
1613 *val = LDAP_MALLOC( sizeof( struct berval ) );
1614 ( *val )->bv_len = len;
1616 if ( escapes == 0 && unescapes == 0 ) {
1617 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1622 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1623 for ( s = 0, d = 0; d < len; ) {
1624 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1626 if ( ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( startPos[ s ] ) )
1627 || ( s == len - 1 && LDAP_DN_NEEDESCAPE_TRAIL( startPos[ s ] ) )
1628 || LDAP_DN_NEEDESCAPE( startPos[ s ] ) ) {
1629 ( *val )->bv_val[ d++ ] =
1632 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1635 hexstr2bin( &startPos[ s ], &c );
1636 ( *val )->bv_val[ d++ ] = c;
1641 * we allow escaping of chars
1642 * that do not need to
1644 ( *val )->bv_val[ d++ ] =
1649 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1653 ( *val )->bv_val[ d ] = '\0';
1654 assert( strlen( ( *val )->bv_val ) == len );
1664 DCE2strval( const char *str, struct berval **val, const char **next, unsigned flags )
1666 const char *p, *startPos, *endPos = NULL;
1667 ber_len_t len, escapes;
1676 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1677 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1679 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1686 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1691 * FIXME: can we accept anything else? I guess we need
1692 * to stop if a value is not legal
1697 * (unescaped) trailing spaces are trimmed must be silently ignored;
1700 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1701 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1702 if ( flags & LDAP_DN_PEDANTIC ) {
1706 /* strip trailing (unescaped) spaces */
1707 for ( endPos = p - 1;
1708 endPos > startPos + 1 &&
1709 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1710 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1717 len = ( endPos ? endPos : p ) - startPos - escapes;
1718 *val = LDAP_MALLOC( sizeof( struct berval ) );
1719 ( *val )->bv_len = len;
1720 if ( escapes == 0 ){
1721 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1726 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1727 for ( s = 0, d = 0; d < len; ) {
1729 * This point is reached only if escapes
1730 * are properly used, so all we need to
1733 if ( LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1737 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1739 ( *val )->bv_val[ d ] = '\0';
1740 assert( strlen( ( *val )->bv_val ) == len );
1749 IA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1751 const char *p, *startPos, *endPos = NULL;
1752 ber_len_t len, escapes;
1765 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1766 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1768 if ( p[ 0 ] == '\0' ) {
1772 if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1773 && ( LDAP_DN_PEDANTIC & flags ) ) {
1778 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1783 * FIXME: can we accept anything else? I guess we need
1784 * to stop if a value is not legal
1788 /* strip trailing (unescaped) spaces */
1790 endPos > startPos + 1 &&
1791 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1792 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1797 *val = LDAP_MALLOC( sizeof( struct berval ) );
1798 len = ( endPos ? endPos : p ) - startPos - escapes;
1799 ( *val )->bv_len = len;
1800 if ( escapes == 0 ) {
1801 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1806 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1807 for ( s = 0, d = 0; d < len; ) {
1808 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1811 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1813 ( *val )->bv_val[ d ] = '\0';
1814 assert( strlen( ( *val )->bv_val ) == len );
1822 quotedIA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1824 const char *p, *startPos, *endPos = NULL;
1826 unsigned escapes = 0;
1835 /* initial quote already eaten */
1836 for ( startPos = p = str; p[ 0 ]; p++ ) {
1838 * According to RFC 1779, the quoted value can
1839 * contain escaped as well as unescaped special values;
1840 * as a consequence we tolerate escaped values
1841 * (e.g. '"\,"' -> '\,') and escape unescaped specials
1842 * (e.g. '","' -> '\,').
1844 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1845 if ( p[ 1 ] == '\0' ) {
1850 if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1851 && ( LDAP_DN_PEDANTIC & flags ) ) {
1853 * do we allow to escape normal chars?
1854 * LDAPv2 does not allow any mechanism
1855 * for escaping chars with '\' and hex
1862 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1864 /* eat closing quotes */
1870 * FIXME: can we accept anything else? I guess we need
1871 * to stop if a value is not legal
1875 if ( endPos == NULL ) {
1879 /* Strip trailing (unescaped) spaces */
1880 for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1884 len = endPos - startPos - escapes;
1886 *val = LDAP_MALLOC( sizeof( struct berval ) );
1887 ( *val )->bv_len = len;
1888 if ( escapes == 0 ) {
1889 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1894 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1895 ( *val )->bv_len = len;
1897 for ( s = d = 0; d < len; ) {
1898 if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1901 ( *val )->bv_val[ d++ ] = str[ s++ ];
1903 ( *val )->bv_val[ d ] = '\0';
1904 assert( strlen( ( *val )->bv_val ) == len );
1913 hexstr2bin( const char *str, char *c )
1923 if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1929 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) ) {
1936 if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1942 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) ) {
1943 *c += c2 - 'a' + 10;
1951 hexstr2binval( const char *str, struct berval **val, const char **next, unsigned flags )
1953 const char *p, *startPos, *endPos = NULL;
1964 for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1965 switch ( LDAP_DN_FORMAT( flags ) ) {
1966 case LDAP_DN_FORMAT_LDAPV3:
1967 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1972 case LDAP_DN_FORMAT_LDAP:
1973 case LDAP_DN_FORMAT_LDAPV2:
1974 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1979 case LDAP_DN_FORMAT_DCE:
1980 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1986 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1987 if ( flags & LDAP_DN_PEDANTIC ) {
1992 for ( ; p[ 0 ]; p++ ) {
1993 switch ( LDAP_DN_FORMAT( flags ) ) {
1994 case LDAP_DN_FORMAT_LDAPV3:
1995 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
2000 case LDAP_DN_FORMAT_LDAP:
2001 case LDAP_DN_FORMAT_LDAPV2:
2002 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
2007 case LDAP_DN_FORMAT_DCE:
2008 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
2017 if ( !LDAP_DN_HEXPAIR( p ) ) {
2024 len = ( ( endPos ? endPos : p ) - startPos ) / 2;
2026 assert( 2 * len == ( endPos ? endPos : p ) - startPos );
2028 *val = LDAP_MALLOC( sizeof( struct berval ) );
2029 if ( *val == NULL ) {
2030 return( LDAP_NO_MEMORY );
2033 ( *val )->bv_len = len;
2034 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
2035 if ( ( *val )->bv_val == NULL ) {
2037 return( LDAP_NO_MEMORY );
2040 for ( s = 0, d = 0; d < len; s += 2, d++ ) {
2043 hexstr2bin( &startPos[ s ], &c );
2045 ( *val )->bv_val[ d ] = c;
2048 ( *val )->bv_val[ d ] = '\0';
2055 * convert a byte in a hexadecimal pair
2058 byte2hexpair( const char *val, char *pair )
2060 static const char hexdig[] = "0123456789abcdef";
2066 * we assume the string has enough room for the hex encoding
2070 pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
2071 pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
2077 * convert a binary value in hexadecimal pairs
2080 binval2hexstr( struct berval *val, char *str )
2087 if ( val->bv_len == 0 ) {
2092 * we assume the string has enough room for the hex encoding
2096 for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
2097 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2104 * Length of the string representation, accounting for escaped hex
2108 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
2110 ber_len_t l, cl = 1;
2117 if ( val->bv_len == 0 ) {
2121 for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
2122 cl = ldap_utf8_charlen( p );
2124 /* illegal utf-8 char! */
2127 } else if ( cl > 1 ) {
2130 for ( cnt = 1; cnt < cl; cnt++ ) {
2131 if ( ( p[ cnt ] & 0x80 ) == 0x00 ) {
2135 /* need to escape it */
2139 * there might be some chars we want to escape in form
2140 * of a couple of hexdigits for optimization purposes
2142 } else if ( LDAP_DN_WILLESCAPE( flags, p[ 0 ] ) ) {
2145 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2146 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2147 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2161 * convert to string representation, escaping with hex the UTF-8 stuff;
2162 * assume the destination has enough room for escaping
2165 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2167 ber_len_t s, d, end;
2173 if ( val->bv_len == 0 ) {
2179 * we assume the string has enough room for the hex encoding
2182 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2183 ber_len_t cl = ldap_utf8_charlen( &val->bv_val[ s ] );
2186 * there might be some chars we want to escape in form
2187 * of a couple of hexdigits for optimization purposes
2189 if ( cl > 1 || LDAP_DN_WILLESCAPE( flags, val->bv_val[ s ] ) ) {
2192 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2198 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2199 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2200 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2203 str[ d++ ] = val->bv_val[ s++ ];
2213 * Length of the IA5 string representation (no UTF-8 allowed)
2216 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
2225 if ( val->bv_len == 0 ) {
2229 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2231 * Turn value into a binary encoded BER
2236 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2237 if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2238 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2239 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2254 * convert to string representation (np UTF-8)
2255 * assume the destination has enough room for escaping
2258 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2260 ber_len_t s, d, end;
2266 if ( val->bv_len == 0 ) {
2271 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2273 * Turn value into a binary encoded BER
2280 * we assume the string has enough room for the hex encoding
2284 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2285 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2286 || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2287 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2290 str[ d++ ] = val->bv_val[ s++ ];
2300 * Length of the (supposedly) DCE string representation,
2301 * accounting for escaped hex of UTF-8 chars
2304 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2313 if ( val->bv_len == 0 ) {
2317 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2319 * FIXME: Turn the value into a binary encoded BER?
2324 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2325 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2340 * convert to (supposedly) DCE string representation,
2341 * escaping with hex the UTF-8 stuff;
2342 * assume the destination has enough room for escaping
2345 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2353 if ( val->bv_len == 0 ) {
2358 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2360 * FIXME: Turn the value into a binary encoded BER?
2368 * we assume the string has enough room for the hex encoding
2372 for ( s = 0, d = 0; s < val->bv_len; ) {
2373 if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2376 str[ d++ ] = val->bv_val[ s++ ];
2386 * Length of the (supposedly) AD canonical string representation,
2387 * accounting for escaped hex of UTF-8 chars
2390 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2399 if ( val->bv_len == 0 ) {
2403 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2405 * FIXME: Turn the value into a binary encoded BER?
2410 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2411 if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2426 * convert to (supposedly) AD string representation,
2427 * escaping with hex the UTF-8 stuff;
2428 * assume the destination has enough room for escaping
2431 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2439 if ( val->bv_len == 0 ) {
2444 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2446 * FIXME: Turn the value into a binary encoded BER?
2454 * we assume the string has enough room for the hex encoding
2458 for ( s = 0, d = 0; s < val->bv_len; ) {
2459 if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2462 str[ d++ ] = val->bv_val[ s++ ];
2472 * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2473 * the forst part of the AD representation of the DN is written in DNS
2474 * form, i.e. dot separated domain name components (as suggested
2475 * by Luke Howard, http://www.padl.com/~lukeh)
2478 dn2domain( LDAPDN *dn, char *str, int *iRDN )
2481 int domain = 0, first = 1;
2482 ber_len_t l = 1; /* we move the null also */
2484 /* we are guaranteed there's enough memory in str */
2490 assert( *iRDN > 0 );
2492 for ( i = *iRDN; i >= 0; i-- ) {
2496 assert( dn[ i ][ 0 ] );
2499 assert( rdn[ 0 ][ 0 ] );
2500 ava = rdn[ 0 ][ 0 ];
2502 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2510 AC_MEMCPY( str, ava->la_value->bv_val,
2511 ava->la_value->bv_len + 1);
2512 l += ava->la_value->bv_len;
2515 AC_MEMCPY( str + ava->la_value->bv_len + 1, str, l);
2516 AC_MEMCPY( str, ava->la_value->bv_val,
2517 ava->la_value->bv_len );
2518 str[ ava->la_value->bv_len ] = '.';
2519 l += ava->la_value->bv_len + 1;
2529 rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
2530 int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2537 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2538 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2540 /* len(type) + '=' + '+' | ',' */
2541 l += ava->la_attr->bv_len + 2;
2543 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2544 /* octothorpe + twice the length */
2545 l += 1 + 2 * ava->la_value->bv_len;
2549 unsigned f = flags | ava->la_flags;
2551 if ( ( *s2l )( ava->la_value, f, &vl ) ) {
2564 rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
2565 int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2570 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2571 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2573 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2574 ava->la_attr->bv_len );
2575 l += ava->la_attr->bv_len;
2579 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2581 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2584 l += 2 * ava->la_value->bv_len;
2588 unsigned f = flags | ava->la_flags;
2590 if ( ( *s2s )( ava->la_value, &str[ l ], f, &vl ) ) {
2595 str[ l++ ] = ( rdn[ iAVA + 1 ] ? '+' : ',' );
2604 rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2611 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2612 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2614 /* len(type) + '=' + ',' | '/' */
2615 l += ava->la_attr->bv_len + 2;
2617 switch ( ava->la_flags ) {
2618 case LDAP_AVA_BINARY:
2619 /* octothorpe + twice the length */
2620 l += 1 + 2 * ava->la_value->bv_len;
2623 case LDAP_AVA_STRING: {
2625 unsigned f = flags | ava->la_flags;
2627 if ( strval2DCEstrlen( ava->la_value, f, &vl ) ) {
2645 rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2650 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2651 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2656 str[ l++ ] = ( iAVA ? ',' : '/' );
2659 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2660 ava->la_attr->bv_len );
2661 l += ava->la_attr->bv_len;
2665 switch ( ava->la_flags ) {
2666 case LDAP_AVA_BINARY:
2668 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2671 l += 2 * ava->la_value->bv_len;
2674 case LDAP_AVA_STRING: {
2676 unsigned f = flags | ava->la_flags;
2678 if ( strval2DCEstr( ava->la_value, &str[ l ], f, &vl ) ) {
2696 rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2706 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2707 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2710 l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
2712 /* FIXME: are binary values allowed in UFN? */
2713 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2714 /* octothorpe + twice the value */
2715 l += 1 + 2 * ava->la_value->bv_len;
2719 unsigned f = flags | ava->la_flags;
2721 if ( strval2strlen( ava->la_value, f, &vl ) ) {
2734 rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
2739 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2740 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2742 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2744 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2747 l += 2 * ava->la_value->bv_len;
2751 unsigned f = flags | ava->la_flags;
2753 if ( strval2str( ava->la_value, &str[ l ], f, &vl ) ) {
2759 if ( rdn[ iAVA + 1 ]) {
2760 AC_MEMCPY( &str[ l ], " + ", 3 );
2764 AC_MEMCPY( &str[ l ], ", ", 2 );
2775 rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2785 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2786 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2791 /* FIXME: are binary values allowed in UFN? */
2792 switch ( ava->la_flags ) {
2793 case LDAP_AVA_BINARY:
2794 /* octothorpe + twice the value */
2795 l += 1 + 2 * ava->la_value->bv_len;
2798 case LDAP_AVA_STRING: {
2800 unsigned f = flags | ava->la_flags;
2802 if ( strval2ADstrlen( ava->la_value, f, &vl ) ) {
2820 rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2825 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2826 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2831 str[ l++ ] = ( iAVA ? ',' : '/' );
2834 switch ( ava->la_flags ) {
2835 case LDAP_AVA_BINARY:
2837 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2840 l += 2 * ava->la_value->bv_len;
2843 case LDAP_AVA_STRING: {
2845 unsigned f = flags | ava->la_flags;
2847 if ( strval2ADstr( ava->la_value, &str[ l ], f, &vl ) ) {
2867 * Returns in str a string representation of rdn based on flags.
2868 * There is some duplication of code between this and ldap_dn2str;
2869 * this is wanted to reduce the allocation of temporary buffers.
2872 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2879 if ( rdn == NULL ) {
2880 *str = LDAP_STRDUP( "" );
2881 return( LDAP_SUCCESS );
2885 * This routine wastes "back" bytes at the end of the string
2889 switch ( LDAP_DN_FORMAT( flags ) ) {
2890 case LDAP_DN_FORMAT_LDAPV3:
2891 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2892 return( LDAP_OTHER );
2896 case LDAP_DN_FORMAT_LDAPV2:
2897 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2898 return( LDAP_OTHER );
2902 case LDAP_DN_FORMAT_UFN:
2903 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2904 return( LDAP_OTHER );
2908 case LDAP_DN_FORMAT_DCE:
2909 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2910 return( LDAP_OTHER );
2914 case LDAP_DN_FORMAT_AD_CANONICAL:
2915 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2916 return( LDAP_OTHER );
2921 return( LDAP_INVALID_DN_SYNTAX );
2924 *str = LDAP_MALLOC( l + 1 );
2926 switch ( LDAP_DN_FORMAT( flags ) ) {
2927 case LDAP_DN_FORMAT_LDAPV3:
2928 rc = rdn2str( rdn, *str, flags, &l, strval2str );
2932 case LDAP_DN_FORMAT_LDAPV2:
2933 rc = rdn2str( rdn, *str, flags, &l, strval2IA5str );
2937 case LDAP_DN_FORMAT_UFN:
2938 rc = rdn2UFNstr( rdn, *str, flags, &l );
2942 case LDAP_DN_FORMAT_DCE:
2943 rc = rdn2DCEstr( rdn, *str, flags, &l, 1 );
2947 case LDAP_DN_FORMAT_AD_CANONICAL:
2948 rc = rdn2ADstr( rdn, *str, flags, &l, 1 );
2953 /* need at least one of the previous */
2954 return( LDAP_OTHER );
2958 ldap_memfree( *str );
2959 return( LDAP_OTHER );
2962 ( *str )[ l - back ] = '\0';
2964 return( LDAP_SUCCESS );
2968 * Very bulk implementation; many optimizations can be performed
2969 * - a NULL dn results in an empty string ""
2972 * a) what do we do if a UTF-8 string must be converted in LDAPv2?
2973 * we must encode it in binary form ('#' + HEXPAIRs)
2974 * b) does DCE/AD support UTF-8?
2975 * no clue; don't think so.
2976 * c) what do we do when binary values must be converted in UTF/DCE/AD?
2977 * use binary encoded BER
2979 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
2982 int rc = LDAP_OTHER;
2985 /* stringifying helpers for LDAPv3/LDAPv2 */
2986 int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2987 int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2991 Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2str(%u)\n%s%s", flags, "", "" );
2996 * a null dn means an empty dn string
2997 * FIXME: better raise an error?
3000 *str = LDAP_STRDUP( "" );
3001 return( LDAP_SUCCESS );
3004 switch ( LDAP_DN_FORMAT( flags ) ) {
3005 case LDAP_DN_FORMAT_LDAPV3:
3006 sv2l = strval2strlen;
3010 case LDAP_DN_FORMAT_LDAPV2:
3011 sv2l = strval2IA5strlen;
3012 sv2s = strval2IA5str;
3015 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3017 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3019 if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
3020 goto return_results;
3026 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3027 rc = LDAP_NO_MEMORY;
3031 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
3033 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3035 if ( rdn2str( rdn, &( *str )[ l ], flags,
3039 goto return_results;
3047 * trim the last ',' (the allocated memory
3048 * is one byte longer than required)
3050 ( *str )[ len - 1 ] = '\0';
3055 case LDAP_DN_FORMAT_UFN: {
3058 * FIXME: quoting from RFC 1781:
3060 To take a distinguished name, and generate a name of this format with
3061 attribute types omitted, the following steps are followed.
3063 1. If the first attribute is of type CommonName, the type may be
3066 2. If the last attribute is of type Country, the type may be
3069 3. If the last attribute is of type Country, the last
3070 Organisation attribute may have the type omitted.
3072 4. All attributes of type OrganisationalUnit may have the type
3073 omitted, unless they are after an Organisation attribute or
3074 the first attribute is of type OrganisationalUnit.
3076 * this should be the pedantic implementation.
3078 * Here the standard implementation reflects
3079 * the one historically provided by OpenLDAP
3080 * (and UMIch, I presume), with the variant
3081 * of spaces and plusses (' + ') separating
3084 * A non-standard but nice implementation could
3085 * be to turn the final "dc" attributes into a
3086 * dot-separated domain.
3088 * Other improvements could involve the use of
3089 * friendly country names and so.
3092 int leftmost_dc = -1;
3094 #endif /* DC_IN_UFN */
3096 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3098 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3100 if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
3101 goto return_results;
3106 if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
3107 if ( leftmost_dc == -1 ) {
3113 #endif /* DC_IN_UFN */
3116 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3117 rc = LDAP_NO_MEMORY;
3122 if ( leftmost_dc == -1 ) {
3123 #endif /* DC_IN_UFN */
3124 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
3126 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3128 if ( rdn2UFNstr( rdn, &( *str )[ l ],
3132 goto return_results;
3138 * trim the last ', ' (the allocated memory
3139 * is two bytes longer than required)
3141 ( *str )[ len - 2 ] = '\0';
3144 last_iRDN = iRDN - 1;
3146 for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
3148 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3150 if ( rdn2UFNstr( rdn, &( *str )[ l ],
3154 goto return_results;
3159 if ( !dn2domain( dn, &( *str )[ l ], &last_iRDN ) ) {
3162 goto return_results;
3165 /* the string is correctly terminated by dn2domain */
3167 #endif /* DC_IN_UFN */
3173 case LDAP_DN_FORMAT_DCE:
3175 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3177 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3179 if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
3180 goto return_results;
3186 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3187 rc = LDAP_NO_MEMORY;
3191 for ( l = 0; iRDN--; ) {
3193 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3195 if ( rdn2DCEstr( rdn, &( *str )[ l ], flags,
3199 goto return_results;
3206 ( *str )[ len ] = '\0';
3211 case LDAP_DN_FORMAT_AD_CANONICAL: {
3214 * Sort of UFN for DCE DNs: a slash ('/') separated
3215 * global->local DN with no types; strictly speaking,
3216 * the naming context should be a domain, which is
3217 * written in DNS-style, e.g. dot-deparated.
3221 * "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3225 * "microsoft.com/People/Bill,Gates"
3227 for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
3229 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3231 if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
3232 goto return_results;
3238 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3239 rc = LDAP_NO_MEMORY;
3244 if ( iRDN && dn2domain( dn, *str, &iRDN ) ) {
3245 for ( l = strlen( *str ); iRDN >= 0 ; iRDN-- ) {
3247 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3249 if ( rdn2ADstr( rdn, &( *str )[ l ],
3250 flags, &rdnl, 0 ) ) {
3253 goto return_results;
3262 * Strictly speaking, AD canonical requires
3263 * a DN to be in the form "..., dc=smtg",
3264 * i.e. terminated by a domain component
3266 if ( flags & LDAP_DN_PEDANTIC ) {
3269 rc = LDAP_INVALID_DN_SYNTAX;
3273 for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3275 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3277 if ( rdn2ADstr( rdn, &( *str )[ l ],
3278 flags, &rdnl, first ) ) {
3281 goto return_results;
3290 ( *str )[ len ] = '\0';
3297 return( LDAP_INVALID_DN_SYNTAX );
3301 Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2str(%s,%u)=%d\n", *str, flags, rc );