3 * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * Copyright (c) 1994 Regents of the University of Michigan.
17 #include <ac/stdlib.h>
20 #include <ac/socket.h>
21 #include <ac/string.h>
26 /* extension to UFN that turns trailing "dc=value" rdns in DNS style,
27 * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */
30 static int dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout );
32 /* from libraries/libldap/schema.c */
33 extern char * parse_numericoid(const char **sp, int *code, const int flags);
35 /* parsing/printing routines */
36 static int str2strval( const char *str, struct berval **val,
37 const char **next, unsigned flags, unsigned *retFlags );
38 static int DCE2strval( const char *str, struct berval **val,
39 const char **next, unsigned flags );
40 static int IA52strval( const char *str, struct berval **val,
41 const char **next, unsigned flags );
42 static int quotedIA52strval( const char *str, struct berval **val,
43 const char **next, unsigned flags );
44 static int hexstr2binval( const char *str, struct berval **val,
45 const char **next, unsigned flags );
46 static int hexstr2bin( const char *str, char *c );
47 static int byte2hexpair( const char *val, char *pair );
48 static int binval2hexstr( struct berval *val, char *str );
49 static int strval2strlen( struct berval *val, unsigned flags,
51 static int strval2str( struct berval *val, char *str, unsigned flags,
53 static int strval2IA5strlen( struct berval *val, unsigned flags,
55 static int strval2IA5str( struct berval *val, char *str, unsigned flags,
57 static int strval2DCEstrlen( struct berval *val, unsigned flags,
59 static int strval2DCEstr( struct berval *val, char *str, unsigned flags,
61 static int strval2ADstrlen( struct berval *val, unsigned flags,
63 static int strval2ADstr( struct berval *val, char *str, unsigned flags,
65 static int dn2domain( LDAPDN *dn, char *str, int *iRDN );
68 static LDAPAVA * ldapava_new(
69 const struct berval *attr, const struct berval *val, unsigned flags );
70 static LDAPRDN * ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava );
71 static LDAPRDN * ldapava_insert_into_rdn(
72 LDAPRDN *rdn, LDAPAVA *ava, unsigned where );
73 static LDAPDN * ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn );
74 static LDAPDN * ldapava_insert_into_dn(
75 LDAPDN *dn, LDAPRDN *rdn, unsigned where );
77 /* Higher level helpers */
78 static int rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
79 int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
80 static int rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
81 int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
82 static int rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
83 static int rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len );
84 static int rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
85 static int rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flag, ber_len_t *len, int first );
86 static int rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
87 static int rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first );
90 * RFC 1823 ldap_get_dn
93 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
98 Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
100 if ( entry == NULL ) {
101 ld->ld_errno = LDAP_PARAM_ERROR;
105 tmp = *entry->lm_ber; /* struct copy */
106 if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
107 ld->ld_errno = LDAP_DECODING_ERROR;
115 * RFC 1823 ldap_dn2ufn
118 ldap_dn2ufn( LDAP_CONST char *dn )
122 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
124 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_UFN );
130 * RFC 1823 ldap_explode_dn
133 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
136 char **values = NULL;
138 unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
140 Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
142 if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP )
147 for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) {
148 char *str, **v = NULL;
150 ldap_rdn2str( tmpDN[ iRDN ][ 0 ], &str, flag );
152 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iRDN ) );
154 LBER_VFREE( values );
155 ldap_dnfree( tmpDN );
159 values[ iRDN ] = str;
161 values[ iRDN ] = NULL;
167 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
170 char **values = NULL;
172 unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
174 Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
177 * we assume this dn is made of one rdn only
179 if ( ldap_str2dn( rdn, &tmpDN, LDAP_DN_FORMAT_LDAP )
184 for ( iAVA = 0; tmpDN[ 0 ][ 0 ][ iAVA ]; iAVA++ ) {
185 ber_len_t l = 0, vl, al = 0;
186 char *str, **v = NULL;
187 LDAPAVA *ava = tmpDN[ 0 ][ 0 ][ iAVA ][ 0 ];
189 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iAVA ) );
195 if ( ava->la_flags == LDAP_AVA_BINARY ) {
196 vl = 1 + 2 * ava->la_value->bv_len;
199 if ( strval2strlen( ava->la_value,
200 ava->la_flags, &vl ) ) {
206 al = ava->la_attr->bv_len;
207 l = vl + ava->la_attr->bv_len + 1;
209 str = LDAP_MALLOC( l + 1 );
210 AC_MEMCPY( str, ava->la_attr->bv_val,
211 ava->la_attr->bv_len );
216 str = LDAP_MALLOC( l + 1 );
219 if ( ava->la_flags == LDAP_AVA_BINARY ) {
221 if ( binval2hexstr( ava->la_value, &str[ al ] ) ) {
226 if ( strval2str( ava->la_value, &str[ al ],
227 ava->la_flags, &vl ) ) {
233 values[ iAVA ] = str;
235 values[ iAVA ] = NULL;
237 ldap_dnfree( tmpDN );
242 LBER_VFREE( values );
243 ldap_dnfree( tmpDN );
248 ldap_dn2dcedn( LDAP_CONST char *dn )
252 Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
254 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_DCE );
260 ldap_dcedn2dn( LDAP_CONST char *dce )
264 Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
266 ( void )dn2dn( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
272 ldap_dn2ad_canonical( LDAP_CONST char *dn )
276 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
278 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP,
279 &out, LDAP_DN_FORMAT_AD_CANONICAL );
285 ldap_dn_normalize( const char *in, unsigned iflags, char **out, unsigned oflags )
289 Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );
291 return dn2dn( in, iflags, out, oflags);
295 * helper that changes the string representation of dnin
296 * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
299 * LDAP_DN_FORMAT_LDAP (rfc 2253 and ldapbis liberal,
300 * plus some rfc 1779)
301 * LDAP_DN_FORMAT_LDAPV3 (rfc 2253 and ldapbis)
302 * LDAP_DN_FORMAT_LDAPV2 (rfc 1779)
303 * LDAP_DN_FORMAT_DCE (?)
305 * fout can be any of the above except
306 * LDAP_DN_FORMAT_LDAP
308 * LDAP_DN_FORMAT_UFN (rfc 1781, partial and with extensions)
309 * LDAP_DN_FORMAT_AD_CANONICAL (?)
312 dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout )
315 LDAPDN *tmpDN = NULL;
321 if ( dnin == NULL ) {
322 return( LDAP_SUCCESS );
325 rc = ldap_str2dn( dnin , &tmpDN, fin );
326 if ( rc != LDAP_SUCCESS ) {
330 rc = ldap_dn2str( tmpDN, dnout, fout );
332 ldap_dnfree( tmpDN );
340 /* #define B4ATTRTYPE 0x0001 */
341 #define B4OIDATTRTYPE 0x0002
342 #define B4STRINGATTRTYPE 0x0003
344 #define B4AVAEQUALS 0x0100
345 #define B4AVASEP 0x0200
346 #define B4RDNSEP 0x0300
347 #define GOTAVA 0x0400
349 #define B4ATTRVALUE 0x0010
350 #define B4STRINGVALUE 0x0020
351 #define B4IA5VALUEQUOTED 0x0030
352 #define B4IA5VALUE 0x0040
353 #define B4BINARYVALUE 0x0050
355 /* Helpers (mostly from slapd.h; maybe it should be rewritten from this) */
356 #define LDAP_DN_ASCII_SPACE(c) \
357 ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
358 #define LDAP_DN_ASCII_LOWER(c) ( (c) >= 'a' && (c) <= 'z' )
359 #define LDAP_DN_ASCII_UPPER(c) ( (c) >= 'A' && (c) <= 'Z' )
360 #define LDAP_DN_ASCII_ALPHA(c) \
361 ( LDAP_DN_ASCII_LOWER(c) || LDAP_DN_ASCII_UPPER(c) )
362 #define LDAP_DN_ASCII_DIGIT(c) ( (c) >= '0' && (c) <= '9' )
363 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) ( (c) >= 'a' && (c) <= 'f' )
364 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) ( (c) >= 'A' && (c) <= 'F' )
365 #define LDAP_DN_ASCII_HEXDIGIT(c) \
366 ( LDAP_DN_ASCII_DIGIT(c) \
367 || LDAP_DN_ASCII_LCASE_HEXALPHA(c) \
368 || LDAP_DN_ASCII_UCASE_HEXALPHA(c) )
369 #define LDAP_DN_ASCII_ALNUM(c) \
370 ( LDAP_DN_ASCII_ALPHA(c) || LDAP_DN_ASCII_DIGIT(c) )
371 #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' )
374 #define LDAP_DN_OID_LEADCHAR(c) ( LDAP_DN_ASCII_DIGIT(c) )
375 #define LDAP_DN_DESC_LEADCHAR(c) ( LDAP_DN_ASCII_ALPHA(c) )
376 #define LDAP_DN_DESC_CHAR(c) ( LDAP_DN_ASCII_ALNUM(c) || (c) == '-' )
377 #define LDAP_DN_LANG_SEP(c) ( (c) == ';' )
378 #define LDAP_DN_ATTRDESC_CHAR(c) \
379 ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
381 /* special symbols */
382 #define LDAP_DN_AVA_EQUALS(c) ( (c) == '=' )
383 #define LDAP_DN_AVA_SEP(c) ( (c) == '+' )
384 #define LDAP_DN_RDN_SEP(c) ( (c) == ',' )
385 #define LDAP_DN_RDN_SEP_V2(c) ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
386 #define LDAP_DN_OCTOTHORPE(c) ( (c) == '#' )
387 #define LDAP_DN_QUOTES(c) ( (c) == '\"' )
388 #define LDAP_DN_ESCAPE(c) ( (c) == '\\' )
389 #define LDAP_DN_VALUE_END(c) \
390 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
391 #define LDAP_DN_NE(c) \
392 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
393 || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
394 #define LDAP_DN_NEEDESCAPE(c) \
395 ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
396 #define LDAP_DN_NEEDESCAPE_LEAD(c) \
397 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) )
398 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
399 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
400 #define LDAP_DN_WILLESCAPE_CHAR( c) \
401 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
402 #define LDAP_DN_IS_PRETTY( f ) ( (f) & LDAP_DN_PRETTY )
403 #define LDAP_DN_WILLESCAPE(f, c) \
404 ( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
407 #define LDAP_DN_VALUE_END_V2(c) \
408 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
410 #define LDAP_DN_V2_SPECIAL(c) \
411 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
412 || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
413 || LDAP_DN_OCTOTHORPE(c) )
414 #define LDAP_DN_V2_PAIR(c) \
415 ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
418 * DCE (mostly from Luke Howard and IBM implementation for AIX)
420 * From: "Application Development Guide - Directory Services" (FIXME: add link?)
421 * Here escapes and valid chars for GDS are considered; as soon as more
422 * specific info is found, the macros will be updated.
424 * Chars: 'a'-'z', 'A'-'Z', '0'-'9',
425 * '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
427 * Metachars: '/', ',', '=', '\'.
429 * the '\' is used to escape other metachars.
435 * Attribute types must start with alphabetic chars and can contain
436 * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
438 #define LDAP_DN_RDN_SEP_DCE(c) ( (c) == '/' )
439 #define LDAP_DN_AVA_SEP_DCE(c) ( (c) == ',' )
440 #define LDAP_DN_ESCAPE_DCE(c) ( LDAP_DN_ESCAPE(c) )
441 #define LDAP_DN_VALUE_END_DCE(c) \
442 ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
443 #define LDAP_DN_NEEDESCAPE_DCE(c) \
444 ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
447 #define LDAP_DN_RDN_SEP_AD(c) ( (c) == '/' )
448 #define LDAP_DN_ESCAPE_AD(c) ( LDAP_DN_ESCAPE(c) )
449 #define LDAP_DN_AVA_SEP_AD(c) ( (c) == ',' ) /* assume same as DCE */
450 #define LDAP_DN_VALUE_END_AD(c) \
451 ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
452 #define LDAP_DN_NEEDESCAPE_AD(c) \
453 ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
456 #define LDAP_DN_HEXPAIR(s) \
457 ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
458 #define LDAP_DC_ATTR "dc"
459 /* better look at the AttributeDescription? */
461 /* FIXME: no composite rdn or non-"dc" types, right?
462 * (what about "dc" in OID form?) */
463 /* FIXME: we do not allow binary values in domain, right? */
464 /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
465 #define LDAP_DN_IS_RDN_DC( rdn ) \
466 ( ( rdn ) && ( rdn )[ 0 ][ 0 ] && !( rdn )[ 1 ] \
467 && ( ( rdn )[ 0 ][ 0 ]->la_flags == LDAP_AVA_STRING ) \
468 && ! strcasecmp( ( rdn )[ 0 ][ 0 ]->la_attr->bv_val, LDAP_DC_ATTR ) )
470 /* Composite rules */
471 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
472 ( LDAP_DN_LDAPV2(f) \
473 || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
474 #define LDAP_DN_ALLOW_SPACES(f) \
475 ( LDAP_DN_LDAPV2(f) \
476 || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
477 #define LDAP_DN_LDAP(f) \
478 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
479 #define LDAP_DN_LDAPV3(f) \
480 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
481 #define LDAP_DN_LDAPV2(f) \
482 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
483 #define LDAP_DN_DCE(f) \
484 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
485 #define LDAP_DN_UFN(f) \
486 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
487 #define LDAP_DN_ADC(f) \
488 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
489 #define LDAP_DN_FORMAT(f) ( (f) & LDAP_DN_FORMAT_MASK )
492 * LDAPAVA helpers (will become part of the API for operations
493 * on structural representations of DNs).
496 ldapava_new( const struct berval *attr, const struct berval *val,
504 ava = LDAP_MALLOC( sizeof( LDAPAVA ) );
506 /* should we test it? */
511 ava->la_attr = ( struct berval * )attr;
512 ava->la_value = ( struct berval * )val;
513 ava->la_flags = flags;
515 ava->la_private = NULL;
521 ldap_avafree( LDAPAVA *ava )
525 /* ava's private must be freed by caller */
526 assert( ava->la_private != NULL );
528 ber_bvfree( ava->la_attr );
529 ber_bvfree( ava->la_value );
535 ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava )
543 for ( i = 0U; rdn[ i ]; i++ ) {
547 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
548 newRDN[ i ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
549 newRDN[ i ][ 0 ] = ava;
550 newRDN[ i + 1 ] = NULL;
556 ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where )
564 for ( i = 0U; rdn[ i ]; i++ ) {
570 /* assume "at end", which corresponds to
571 * ldapava_append_to_rdn */
574 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
576 /* data after insert point */
577 AC_MEMCPY( &newRDN[ where + 1 ], &newRDN[ where ],
578 ( i - where ) * sizeof( LDAPRDN * ) );
580 newRDN[ where ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
581 newRDN[ where ][ 0 ] = ava;
582 newRDN[ i + 1 ] = NULL;
588 ldap_rdnfree( LDAPRDN *rdn )
596 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
597 assert( rdn[ iAVA ][ 0 ] );
599 ldap_avafree( rdn[ iAVA ][ 0 ] );
606 ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn )
614 for ( i = 0U; dn[ i ]; i++ ) {
618 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
619 newDN[ i ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
620 newDN[ i ][ 0 ] = rdn;
621 newDN[ i + 1 ] = NULL;
627 ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where )
635 for ( i = 0U; dn[ i ]; i++ ) {
641 /* assume "at end", which corresponds to
642 * ldapava_append_to_dn */
645 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
647 /* data after insert point */
648 AC_MEMCPY( &newDN[ where + 1 ], &newDN[ where ],
649 ( i - where ) * sizeof( LDAPDN * ) );
651 newDN[ where ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
652 newDN[ where ][ 0 ] = rdn;
653 newDN[ i + 1 ] = NULL;
659 ldap_dnfree( LDAPDN *dn )
667 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
668 assert( dn[ iRDN ][ 0 ] );
670 ldap_rdnfree( dn[ iRDN ][ 0 ] );
677 * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
678 * into a structural representation of the DN, by separating attribute
679 * types and values encoded in the more appropriate form, which is
680 * string or OID for attribute types and binary form of the BER encoded
681 * value or Unicode string. Formats different from LDAPv3 are parsed
682 * according to their own rules and turned into the more appropriate
683 * form according to LDAPv3.
685 * NOTE: I realize the code is getting spaghettish; it is rather
686 * experimental and will hopefully turn into something more simple
687 * and readable as soon as it works as expected.
691 ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
694 int rc = LDAP_INVALID_DN_SYNTAX;
696 LDAPDN *newDN = NULL;
697 LDAPRDN *newRDN = NULL;
702 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );
706 switch ( LDAP_DN_FORMAT( flags ) ) {
707 case LDAP_DN_FORMAT_LDAP:
708 case LDAP_DN_FORMAT_LDAPV3:
709 case LDAP_DN_FORMAT_LDAPV2:
710 case LDAP_DN_FORMAT_DCE:
713 /* unsupported in str2dn */
714 case LDAP_DN_FORMAT_UFN:
715 case LDAP_DN_FORMAT_AD_CANONICAL:
716 return( LDAP_INVALID_DN_SYNTAX );
719 return( LDAP_OTHER );
722 if ( str[ 0 ] == '\0' ) {
723 return( LDAP_SUCCESS );
727 if ( LDAP_DN_DCE( flags ) ) {
730 * (from Luke Howard: thnx) A RDN separator is required
731 * at the beginning of an (absolute) DN.
733 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
738 } else if ( LDAP_DN_LDAP( flags ) ) {
740 * if dn starts with '/' let's make it a DCE dn
742 if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
743 flags |= LDAP_DN_FORMAT_DCE;
748 for ( ; p[ 0 ]; p++ ) {
752 err = ldap_str2rdn( p, &newRDN, &p, flags );
753 if ( err != LDAP_SUCCESS ) {
758 * We expect a rdn separator
761 switch ( LDAP_DN_FORMAT( flags ) ) {
762 case LDAP_DN_FORMAT_LDAPV3:
763 if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
769 case LDAP_DN_FORMAT_LDAP:
770 case LDAP_DN_FORMAT_LDAPV2:
771 if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
777 case LDAP_DN_FORMAT_DCE:
778 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
787 if ( LDAP_DN_DCE( flags ) ) {
788 /* add in reversed order */
789 dn = ldapava_insert_into_dn( newDN, newRDN, 0 );
791 dn = ldapava_append_to_dn( newDN, newRDN );
802 if ( p[ 0 ] == '\0' ) {
805 * the DN is over, phew
814 ldap_rdnfree( newRDN );
818 ldap_dnfree( newDN );
824 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
833 * Parses a relative DN according to flags up to a rdn separator
834 * or to the end of str.
835 * Returns the rdn and a pointer to the string continuation, which
836 * corresponds to the rdn separator or to '\0' in case the string is over.
839 ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
843 int rc = LDAP_INVALID_DN_SYNTAX;
844 int attrTypeEncoding = LDAP_AVA_STRING,
845 attrValueEncoding = LDAP_AVA_STRING;
847 struct berval *attrType = NULL;
848 struct berval *attrValue = NULL;
850 LDAPRDN *newRDN = NULL;
856 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );
861 switch ( LDAP_DN_FORMAT( flags ) ) {
862 case LDAP_DN_FORMAT_LDAP:
863 case LDAP_DN_FORMAT_LDAPV3:
864 case LDAP_DN_FORMAT_LDAPV2:
865 case LDAP_DN_FORMAT_DCE:
868 /* unsupported in str2dn */
869 case LDAP_DN_FORMAT_UFN:
870 case LDAP_DN_FORMAT_AD_CANONICAL:
871 return( LDAP_INVALID_DN_SYNTAX );
874 return( LDAP_OTHER );
877 if ( str[ 0 ] == '\0' ) {
878 return( LDAP_SUCCESS );
882 for ( ; p[ 0 ] || state == GOTAVA; ) {
885 * The parser in principle advances one token a time,
886 * or toggles state if preferable.
891 * an AttributeType can be encoded as:
892 * - its string representation; in detail, implementations
893 * MUST recognize AttributeType string type names listed
894 * in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
895 * MAY recognize other names.
896 * - its numeric OID (a dotted decimal string); in detail
897 * RFC 2253 asserts that ``Implementations MUST allow
898 * an oid in the attribute type to be prefixed by one
899 * of the character strings "oid." or "OID."''. As soon
900 * as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253
901 * I'm not sure whether this is required or not any
902 * longer; to be liberal, we still implement it.
905 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
906 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
913 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
914 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
919 /* whitespace is allowed (and trimmed) */
921 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
926 /* error: we expected an AVA */
932 if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
933 state = B4OIDATTRTYPE;
937 /* else must be alpha */
938 if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
942 /* LDAPv2 "oid." prefix */
943 if ( LDAP_DN_LDAPV2( flags ) ) {
945 * to be overly pedantic, we only accept
948 if ( flags & LDAP_DN_PEDANTIC ) {
949 if ( !strncmp( p, "OID.", 4 )
950 || !strncmp( p, "oid.", 4 ) ) {
952 state = B4OIDATTRTYPE;
956 if ( !strncasecmp( p, "oid.", 4 ) ) {
958 state = B4OIDATTRTYPE;
964 state = B4STRINGATTRTYPE;
967 case B4OIDATTRTYPE: {
968 int err = LDAP_SUCCESS;
971 type = parse_numericoid( &p, &err, 0 );
972 if ( type == NULL ) {
975 attrType = LDAP_MALLOC( sizeof( struct berval ) );
976 if ( attrType== NULL ) {
980 attrType->bv_val = type;
981 attrType->bv_len = strlen( type );
982 attrTypeEncoding = LDAP_AVA_BINARY;
988 case B4STRINGATTRTYPE: {
989 const char *startPos, *endPos = NULL;
993 * the starting char has been found to be
994 * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
995 * FIXME: DCE attr types seem to have a more
996 * restrictive syntax (no '-' ...)
998 for ( startPos = p++; p[ 0 ]; p++ ) {
999 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
1003 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
1006 * RFC 2253 does not explicitly
1007 * allow lang extensions to attribute
1010 if ( flags & LDAP_DN_PEDANTIC ) {
1015 * we trim ';' and following lang
1016 * and so from attribute types
1019 for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
1020 || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
1028 len = ( endPos ? endPos : p ) - startPos;
1033 assert( attrType == NULL );
1034 attrType = LDAP_MALLOC( sizeof( struct berval ) );
1035 if ( attrType == NULL ) {
1036 rc = LDAP_NO_MEMORY;
1039 attrType->bv_val = LDAP_STRNDUP( startPos, len );
1040 if ( attrType->bv_val == NULL ) {
1041 rc = LDAP_NO_MEMORY;
1044 attrType->bv_len = len;
1045 attrTypeEncoding = LDAP_AVA_STRING;
1048 * here we need to decide whether to use it as is
1049 * or turn it in OID form; as a consequence, we
1050 * need to decide whether to binary encode the value
1053 state = B4AVAEQUALS;
1058 /* spaces may not be allowed */
1059 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1060 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1065 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1070 /* need equal sign */
1071 if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1076 /* spaces may not be allowed */
1077 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1078 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1083 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1089 * octothorpe means a BER encoded value will follow
1090 * FIXME: I don't think DCE will allow it
1092 if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1094 attrValueEncoding = LDAP_AVA_BINARY;
1095 state = B4BINARYVALUE;
1099 /* STRING value expected */
1102 * if we're pedantic, an attribute type in OID form
1103 * SHOULD imply a BER encoded attribute value; we
1104 * should at least issue a warning
1106 if ( ( flags & LDAP_DN_PEDANTIC )
1107 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1108 /* OID attrType SHOULD use binary encoding */
1112 attrValueEncoding = LDAP_AVA_STRING;
1115 * LDAPv2 allows the attribute value to be quoted;
1116 * also, IA5 values are expected, in principle
1118 if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1119 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1121 state = B4IA5VALUEQUOTED;
1125 if ( LDAP_DN_LDAPV2( flags ) ) {
1132 * here STRING means RFC 2253 string
1133 * FIXME: what about DCE strings?
1135 state = B4STRINGVALUE;
1139 if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
1147 switch ( LDAP_DN_FORMAT( flags ) ) {
1148 case LDAP_DN_FORMAT_LDAP:
1149 case LDAP_DN_FORMAT_LDAPV3:
1150 if ( str2strval( p, &attrValue, &p, flags,
1151 &attrValueEncoding ) ) {
1156 case LDAP_DN_FORMAT_DCE:
1157 if ( DCE2strval( p, &attrValue, &p, flags ) ) {
1170 if ( IA52strval( p, &attrValue, &p, flags ) ) {
1177 case B4IA5VALUEQUOTED:
1179 /* lead quote already stripped */
1180 if ( quotedIA52strval( p, &attrValue,
1194 * we accept empty values
1196 ava = ldapava_new( attrType, attrValue,
1197 attrValueEncoding );
1198 if ( ava == NULL ) {
1199 rc = LDAP_NO_MEMORY;
1203 rdn = ldapava_append_to_rdn( newRDN, ava );
1204 if ( rdn == NULL ) {
1205 rc = LDAP_NO_MEMORY;
1211 * if we got an AVA separator ('+', or ',' for DCE )
1212 * we expect a new AVA for this RDN; otherwise
1213 * we add the RDN to the DN
1215 switch ( LDAP_DN_FORMAT( flags ) ) {
1216 case LDAP_DN_FORMAT_LDAP:
1217 case LDAP_DN_FORMAT_LDAPV3:
1218 case LDAP_DN_FORMAT_LDAPV2:
1219 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1224 case LDAP_DN_FORMAT_DCE:
1225 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1233 * the RDN is over, phew
1240 /* they should have been used in an AVA */
1256 /* They are set to NULL after they're used in an AVA */
1258 ber_bvfree( attrType );
1262 ber_bvfree( attrValue );
1266 ldap_rdnfree( newRDN );
1272 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n",
1280 * reads in a UTF-8 string value, unescaping stuff:
1281 * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1282 * '\' + HEXPAIR(p) -> unhex(p)
1285 str2strval( const char *str, struct berval **val, const char **next, unsigned flags, unsigned *retFlags )
1287 const char *p, *startPos, *endPos = NULL;
1288 ber_len_t len, escapes, unescapes;
1297 for ( startPos = p = str, escapes = 0, unescapes = 0; p[ 0 ]; p++ ) {
1298 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1300 if ( p[ 0 ] == '\0' ) {
1303 if ( ( p == startPos + 1 && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1304 || ( LDAP_DN_VALUE_END( p[ 1 ] ) && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
1305 || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1310 if ( LDAP_DN_HEXPAIR( p ) ) {
1313 hexstr2bin( p, &c );
1316 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1319 * we assume the string is UTF-8
1321 *retFlags = LDAP_AVA_NONPRINTABLE;
1328 if ( LDAP_DN_PEDANTIC & flags ) {
1332 * FIXME: we allow escaping
1333 * of chars that don't need
1334 * to and do not belong to
1335 * HEXDIGITS (we also allow
1336 * single hexdigit; maybe we
1341 } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) )
1342 || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1345 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1347 * FIXME: maybe we can add
1348 * escapes if not pedantic?
1355 * we do allow unescaped spaces at the end
1356 * of the value only in non-pedantic mode
1358 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1359 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1360 if ( flags & LDAP_DN_PEDANTIC ) {
1364 /* strip trailing (unescaped) spaces */
1365 for ( endPos = p - 1;
1366 endPos > startPos + 1 &&
1367 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1368 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1375 * FIXME: test memory?
1377 len = ( endPos ? endPos : p ) - startPos - escapes - unescapes;
1378 *val = LDAP_MALLOC( sizeof( struct berval ) );
1379 ( *val )->bv_len = len;
1381 if ( escapes == 0 && unescapes == 0 ) {
1382 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1387 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1388 for ( s = 0, d = 0; d < len; ) {
1389 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1391 if ( ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( startPos[ s ] ) )
1392 || ( s == len - 1 && LDAP_DN_NEEDESCAPE_TRAIL( startPos[ s ] ) )
1393 || LDAP_DN_NEEDESCAPE( startPos[ s ] ) ) {
1394 ( *val )->bv_val[ d++ ] =
1397 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1400 hexstr2bin( &startPos[ s ], &c );
1401 ( *val )->bv_val[ d++ ] = c;
1406 * we allow escaping of chars
1407 * that do not need to
1409 ( *val )->bv_val[ d++ ] =
1414 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1418 ( *val )->bv_val[ d ] = '\0';
1419 assert( strlen( ( *val )->bv_val ) == len );
1429 DCE2strval( const char *str, struct berval **val, const char **next, unsigned flags )
1431 const char *p, *startPos, *endPos = NULL;
1432 ber_len_t len, escapes;
1441 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1442 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1444 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1451 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1456 * FIXME: can we accept anything else? I guess we need
1457 * to stop if a value is not legal
1462 * (unescaped) trailing spaces are trimmed must be silently ignored;
1465 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1466 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1467 if ( flags & LDAP_DN_PEDANTIC ) {
1471 /* strip trailing (unescaped) spaces */
1472 for ( endPos = p - 1;
1473 endPos > startPos + 1 &&
1474 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1475 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1482 len = ( endPos ? endPos : p ) - startPos - escapes;
1483 *val = LDAP_MALLOC( sizeof( struct berval ) );
1484 ( *val )->bv_len = len;
1485 if ( escapes == 0 ){
1486 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1491 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1492 for ( s = 0, d = 0; d < len; ) {
1494 * This point is reached only if escapes
1495 * are properly used, so all we need to
1498 if ( LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1502 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1504 ( *val )->bv_val[ d ] = '\0';
1505 assert( strlen( ( *val )->bv_val ) == len );
1514 IA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1516 const char *p, *startPos, *endPos = NULL;
1517 ber_len_t len, escapes;
1530 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1531 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1533 if ( p[ 0 ] == '\0' ) {
1537 if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1538 && ( LDAP_DN_PEDANTIC & flags ) ) {
1543 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1548 * FIXME: can we accept anything else? I guess we need
1549 * to stop if a value is not legal
1553 /* strip trailing (unescaped) spaces */
1555 endPos > startPos + 1 &&
1556 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1557 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1562 *val = LDAP_MALLOC( sizeof( struct berval ) );
1563 len = ( endPos ? endPos : p ) - startPos - escapes;
1564 ( *val )->bv_len = len;
1565 if ( escapes == 0 ) {
1566 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1571 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1572 for ( s = 0, d = 0; d < len; ) {
1573 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1576 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1578 ( *val )->bv_val[ d ] = '\0';
1579 assert( strlen( ( *val )->bv_val ) == len );
1587 quotedIA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1589 const char *p, *startPos, *endPos = NULL;
1591 unsigned escapes = 0;
1600 /* initial quote already eaten */
1601 for ( startPos = p = str; p[ 0 ]; p++ ) {
1603 * According to RFC 1779, the quoted value can
1604 * contain escaped as well as unescaped special values;
1605 * as a consequence we tolerate escaped values
1606 * (e.g. '"\,"' -> '\,') and escape unescaped specials
1607 * (e.g. '","' -> '\,').
1609 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1610 if ( p[ 1 ] == '\0' ) {
1615 if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1616 && ( LDAP_DN_PEDANTIC & flags ) ) {
1618 * do we allow to escape normal chars?
1619 * LDAPv2 does not allow any mechanism
1620 * for escaping chars with '\' and hex
1627 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1629 /* eat closing quotes */
1635 * FIXME: can we accept anything else? I guess we need
1636 * to stop if a value is not legal
1640 if ( endPos == NULL ) {
1644 /* Strip trailing (unescaped) spaces */
1645 for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1649 len = endPos - startPos - escapes;
1651 *val = LDAP_MALLOC( sizeof( struct berval ) );
1652 ( *val )->bv_len = len;
1653 if ( escapes == 0 ) {
1654 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1659 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1660 ( *val )->bv_len = len;
1662 for ( s = d = 0; d < len; ) {
1663 if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1666 ( *val )->bv_val[ d++ ] = str[ s++ ];
1668 ( *val )->bv_val[ d ] = '\0';
1669 assert( strlen( ( *val )->bv_val ) == len );
1678 hexstr2bin( const char *str, char *c )
1688 if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1694 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) ) {
1701 if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1707 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) ) {
1708 *c += c2 - 'a' + 10;
1716 hexstr2binval( const char *str, struct berval **val, const char **next, unsigned flags )
1718 const char *p, *startPos, *endPos = NULL;
1729 for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1730 switch ( LDAP_DN_FORMAT( flags ) ) {
1731 case LDAP_DN_FORMAT_LDAPV3:
1732 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1737 case LDAP_DN_FORMAT_LDAP:
1738 case LDAP_DN_FORMAT_LDAPV2:
1739 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1744 case LDAP_DN_FORMAT_DCE:
1745 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1751 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1752 if ( flags & LDAP_DN_PEDANTIC ) {
1757 for ( ; p[ 0 ]; p++ ) {
1758 switch ( LDAP_DN_FORMAT( flags ) ) {
1759 case LDAP_DN_FORMAT_LDAPV3:
1760 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1765 case LDAP_DN_FORMAT_LDAP:
1766 case LDAP_DN_FORMAT_LDAPV2:
1767 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1772 case LDAP_DN_FORMAT_DCE:
1773 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1782 if ( !LDAP_DN_HEXPAIR( p ) ) {
1789 len = ( ( endPos ? endPos : p ) - startPos ) / 2;
1791 assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
1793 *val = LDAP_MALLOC( sizeof( struct berval ) );
1794 if ( *val == NULL ) {
1795 return( LDAP_NO_MEMORY );
1798 ( *val )->bv_len = len;
1799 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1800 if ( ( *val )->bv_val == NULL ) {
1802 return( LDAP_NO_MEMORY );
1805 for ( s = 0, d = 0; d < len; s += 2, d++ ) {
1808 hexstr2bin( &startPos[ s ], &c );
1810 ( *val )->bv_val[ d ] = c;
1813 ( *val )->bv_val[ d ] = '\0';
1820 * convert a byte in a hexadecimal pair
1823 byte2hexpair( const char *val, char *pair )
1825 static const char hexdig[] = "0123456789abcdef";
1831 * we assume the string has enough room for the hex encoding
1835 pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
1836 pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
1842 * convert a binary value in hexadecimal pairs
1845 binval2hexstr( struct berval *val, char *str )
1852 if ( val->bv_len == 0 ) {
1857 * we assume the string has enough room for the hex encoding
1861 for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
1862 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1869 * Length of the string representation, accounting for escaped hex
1873 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
1875 ber_len_t l, cl = 1;
1877 int escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3;
1883 if ( val->bv_len == 0 ) {
1887 for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
1888 cl = ldap_utf8_charlen( p );
1890 /* illegal utf-8 char! */
1893 } else if ( cl > 1 ) {
1896 for ( cnt = 1; cnt < cl; cnt++ ) {
1897 if ( ( p[ cnt ] & 0x80 ) == 0x00 ) {
1901 l += escaped_byte_len * cl;
1904 * there might be some chars we want to escape in form
1905 * of a couple of hexdigits for optimization purposes
1907 } else if ( LDAP_DN_WILLESCAPE( flags, p[ 0 ] ) ) {
1910 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
1911 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1912 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
1926 * convert to string representation, escaping with hex the UTF-8 stuff;
1927 * assume the destination has enough room for escaping
1930 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
1932 ber_len_t s, d, end;
1938 if ( val->bv_len == 0 ) {
1944 * we assume the string has enough room for the hex encoding
1947 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
1948 ber_len_t cl = ldap_utf8_charlen( &val->bv_val[ s ] );
1951 * there might be some chars we want to escape in form
1952 * of a couple of hexdigits for optimization purposes
1954 if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) )
1955 || LDAP_DN_WILLESCAPE( flags, val->bv_val[ s ] ) ) {
1958 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1963 } else if ( cl > 1 ) {
1965 str[ d++ ] = val->bv_val[ s++ ];
1969 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
1970 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
1971 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
1974 str[ d++ ] = val->bv_val[ s++ ];
1984 * Length of the IA5 string representation (no UTF-8 allowed)
1987 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
1996 if ( val->bv_len == 0 ) {
2000 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2002 * Turn value into a binary encoded BER
2007 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2008 if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2009 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2010 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2025 * convert to string representation (np UTF-8)
2026 * assume the destination has enough room for escaping
2029 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2031 ber_len_t s, d, end;
2037 if ( val->bv_len == 0 ) {
2042 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2044 * Turn value into a binary encoded BER
2051 * we assume the string has enough room for the hex encoding
2055 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2056 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2057 || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2058 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2061 str[ d++ ] = val->bv_val[ s++ ];
2071 * Length of the (supposedly) DCE string representation,
2072 * accounting for escaped hex of UTF-8 chars
2075 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2084 if ( val->bv_len == 0 ) {
2088 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2090 * FIXME: Turn the value into a binary encoded BER?
2095 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2096 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2111 * convert to (supposedly) DCE string representation,
2112 * escaping with hex the UTF-8 stuff;
2113 * assume the destination has enough room for escaping
2116 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2124 if ( val->bv_len == 0 ) {
2129 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2131 * FIXME: Turn the value into a binary encoded BER?
2139 * we assume the string has enough room for the hex encoding
2143 for ( s = 0, d = 0; s < val->bv_len; ) {
2144 if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2147 str[ d++ ] = val->bv_val[ s++ ];
2157 * Length of the (supposedly) AD canonical string representation,
2158 * accounting for escaped hex of UTF-8 chars
2161 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2170 if ( val->bv_len == 0 ) {
2174 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2176 * FIXME: Turn the value into a binary encoded BER?
2181 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2182 if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2197 * convert to (supposedly) AD string representation,
2198 * escaping with hex the UTF-8 stuff;
2199 * assume the destination has enough room for escaping
2202 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2210 if ( val->bv_len == 0 ) {
2215 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2217 * FIXME: Turn the value into a binary encoded BER?
2225 * we assume the string has enough room for the hex encoding
2229 for ( s = 0, d = 0; s < val->bv_len; ) {
2230 if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2233 str[ d++ ] = val->bv_val[ s++ ];
2243 * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2244 * the forst part of the AD representation of the DN is written in DNS
2245 * form, i.e. dot separated domain name components (as suggested
2246 * by Luke Howard, http://www.padl.com/~lukeh)
2249 dn2domain( LDAPDN *dn, char *str, int *iRDN )
2252 int domain = 0, first = 1;
2253 ber_len_t l = 1; /* we move the null also */
2255 /* we are guaranteed there's enough memory in str */
2261 assert( *iRDN > 0 );
2263 for ( i = *iRDN; i >= 0; i-- ) {
2267 assert( dn[ i ][ 0 ] );
2270 assert( rdn[ 0 ][ 0 ] );
2271 ava = rdn[ 0 ][ 0 ];
2273 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2281 AC_MEMCPY( str, ava->la_value->bv_val,
2282 ava->la_value->bv_len + 1);
2283 l += ava->la_value->bv_len;
2286 AC_MEMCPY( str + ava->la_value->bv_len + 1, str, l);
2287 AC_MEMCPY( str, ava->la_value->bv_val,
2288 ava->la_value->bv_len );
2289 str[ ava->la_value->bv_len ] = '.';
2290 l += ava->la_value->bv_len + 1;
2300 rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
2301 int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2308 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2309 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2311 /* len(type) + '=' + '+' | ',' */
2312 l += ava->la_attr->bv_len + 2;
2314 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2315 /* octothorpe + twice the length */
2316 l += 1 + 2 * ava->la_value->bv_len;
2320 unsigned f = flags | ava->la_flags;
2322 if ( ( *s2l )( ava->la_value, f, &vl ) ) {
2335 rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
2336 int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2341 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2342 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2344 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2345 ava->la_attr->bv_len );
2346 l += ava->la_attr->bv_len;
2350 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2352 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2355 l += 2 * ava->la_value->bv_len;
2359 unsigned f = flags | ava->la_flags;
2361 if ( ( *s2s )( ava->la_value, &str[ l ], f, &vl ) ) {
2366 str[ l++ ] = ( rdn[ iAVA + 1 ] ? '+' : ',' );
2375 rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2382 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2383 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2385 /* len(type) + '=' + ',' | '/' */
2386 l += ava->la_attr->bv_len + 2;
2388 switch ( ava->la_flags ) {
2389 case LDAP_AVA_BINARY:
2390 /* octothorpe + twice the length */
2391 l += 1 + 2 * ava->la_value->bv_len;
2394 case LDAP_AVA_STRING: {
2396 unsigned f = flags | ava->la_flags;
2398 if ( strval2DCEstrlen( ava->la_value, f, &vl ) ) {
2416 rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2421 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2422 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2427 str[ l++ ] = ( iAVA ? ',' : '/' );
2430 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2431 ava->la_attr->bv_len );
2432 l += ava->la_attr->bv_len;
2436 switch ( ava->la_flags ) {
2437 case LDAP_AVA_BINARY:
2439 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2442 l += 2 * ava->la_value->bv_len;
2445 case LDAP_AVA_STRING: {
2447 unsigned f = flags | ava->la_flags;
2449 if ( strval2DCEstr( ava->la_value, &str[ l ], f, &vl ) ) {
2467 rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2477 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2478 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2481 l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
2483 /* FIXME: are binary values allowed in UFN? */
2484 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2485 /* octothorpe + twice the value */
2486 l += 1 + 2 * ava->la_value->bv_len;
2490 unsigned f = flags | ava->la_flags;
2492 if ( strval2strlen( ava->la_value, f, &vl ) ) {
2505 rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
2510 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2511 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2513 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2515 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2518 l += 2 * ava->la_value->bv_len;
2522 unsigned f = flags | ava->la_flags;
2524 if ( strval2str( ava->la_value, &str[ l ], f, &vl ) ) {
2530 if ( rdn[ iAVA + 1 ]) {
2531 AC_MEMCPY( &str[ l ], " + ", 3 );
2535 AC_MEMCPY( &str[ l ], ", ", 2 );
2546 rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2556 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2557 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2562 /* FIXME: are binary values allowed in UFN? */
2563 switch ( ava->la_flags ) {
2564 case LDAP_AVA_BINARY:
2565 /* octothorpe + twice the value */
2566 l += 1 + 2 * ava->la_value->bv_len;
2569 case LDAP_AVA_STRING: {
2571 unsigned f = flags | ava->la_flags;
2573 if ( strval2ADstrlen( ava->la_value, f, &vl ) ) {
2591 rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2596 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2597 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2602 str[ l++ ] = ( iAVA ? ',' : '/' );
2605 switch ( ava->la_flags ) {
2606 case LDAP_AVA_BINARY:
2608 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2611 l += 2 * ava->la_value->bv_len;
2614 case LDAP_AVA_STRING: {
2616 unsigned f = flags | ava->la_flags;
2618 if ( strval2ADstr( ava->la_value, &str[ l ], f, &vl ) ) {
2638 * Returns in str a string representation of rdn based on flags.
2639 * There is some duplication of code between this and ldap_dn2str;
2640 * this is wanted to reduce the allocation of temporary buffers.
2643 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2650 if ( rdn == NULL ) {
2651 *str = LDAP_STRDUP( "" );
2652 return( LDAP_SUCCESS );
2656 * This routine wastes "back" bytes at the end of the string
2660 switch ( LDAP_DN_FORMAT( flags ) ) {
2661 case LDAP_DN_FORMAT_LDAPV3:
2662 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2663 return( LDAP_OTHER );
2667 case LDAP_DN_FORMAT_LDAPV2:
2668 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2669 return( LDAP_OTHER );
2673 case LDAP_DN_FORMAT_UFN:
2674 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2675 return( LDAP_OTHER );
2679 case LDAP_DN_FORMAT_DCE:
2680 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2681 return( LDAP_OTHER );
2685 case LDAP_DN_FORMAT_AD_CANONICAL:
2686 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2687 return( LDAP_OTHER );
2692 return( LDAP_INVALID_DN_SYNTAX );
2695 *str = LDAP_MALLOC( l + 1 );
2697 switch ( LDAP_DN_FORMAT( flags ) ) {
2698 case LDAP_DN_FORMAT_LDAPV3:
2699 rc = rdn2str( rdn, *str, flags, &l, strval2str );
2703 case LDAP_DN_FORMAT_LDAPV2:
2704 rc = rdn2str( rdn, *str, flags, &l, strval2IA5str );
2708 case LDAP_DN_FORMAT_UFN:
2709 rc = rdn2UFNstr( rdn, *str, flags, &l );
2713 case LDAP_DN_FORMAT_DCE:
2714 rc = rdn2DCEstr( rdn, *str, flags, &l, 1 );
2718 case LDAP_DN_FORMAT_AD_CANONICAL:
2719 rc = rdn2ADstr( rdn, *str, flags, &l, 1 );
2724 /* need at least one of the previous */
2725 return( LDAP_OTHER );
2729 ldap_memfree( *str );
2730 return( LDAP_OTHER );
2733 ( *str )[ l - back ] = '\0';
2735 return( LDAP_SUCCESS );
2739 * Very bulk implementation; many optimizations can be performed
2740 * - a NULL dn results in an empty string ""
2743 * a) what do we do if a UTF-8 string must be converted in LDAPv2?
2744 * we must encode it in binary form ('#' + HEXPAIRs)
2745 * b) does DCE/AD support UTF-8?
2746 * no clue; don't think so.
2747 * c) what do we do when binary values must be converted in UTF/DCE/AD?
2748 * use binary encoded BER
2750 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
2753 int rc = LDAP_OTHER;
2756 /* stringifying helpers for LDAPv3/LDAPv2 */
2757 int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2758 int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2762 Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2str(%u)\n%s%s", flags, "", "" );
2767 * a null dn means an empty dn string
2768 * FIXME: better raise an error?
2771 *str = LDAP_STRDUP( "" );
2772 return( LDAP_SUCCESS );
2775 switch ( LDAP_DN_FORMAT( flags ) ) {
2776 case LDAP_DN_FORMAT_LDAPV3:
2777 sv2l = strval2strlen;
2781 case LDAP_DN_FORMAT_LDAPV2:
2782 sv2l = strval2IA5strlen;
2783 sv2s = strval2IA5str;
2786 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2788 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2790 if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
2791 goto return_results;
2797 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2798 rc = LDAP_NO_MEMORY;
2802 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
2804 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2806 if ( rdn2str( rdn, &( *str )[ l ], flags,
2810 goto return_results;
2818 * trim the last ',' (the allocated memory
2819 * is one byte longer than required)
2821 ( *str )[ len - 1 ] = '\0';
2826 case LDAP_DN_FORMAT_UFN: {
2829 * FIXME: quoting from RFC 1781:
2831 To take a distinguished name, and generate a name of this format with
2832 attribute types omitted, the following steps are followed.
2834 1. If the first attribute is of type CommonName, the type may be
2837 2. If the last attribute is of type Country, the type may be
2840 3. If the last attribute is of type Country, the last
2841 Organisation attribute may have the type omitted.
2843 4. All attributes of type OrganisationalUnit may have the type
2844 omitted, unless they are after an Organisation attribute or
2845 the first attribute is of type OrganisationalUnit.
2847 * this should be the pedantic implementation.
2849 * Here the standard implementation reflects
2850 * the one historically provided by OpenLDAP
2851 * (and UMIch, I presume), with the variant
2852 * of spaces and plusses (' + ') separating
2855 * A non-standard but nice implementation could
2856 * be to turn the final "dc" attributes into a
2857 * dot-separated domain.
2859 * Other improvements could involve the use of
2860 * friendly country names and so.
2863 int leftmost_dc = -1;
2865 #endif /* DC_IN_UFN */
2867 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2869 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2871 if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
2872 goto return_results;
2877 if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
2878 if ( leftmost_dc == -1 ) {
2884 #endif /* DC_IN_UFN */
2887 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2888 rc = LDAP_NO_MEMORY;
2893 if ( leftmost_dc == -1 ) {
2894 #endif /* DC_IN_UFN */
2895 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
2897 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2899 if ( rdn2UFNstr( rdn, &( *str )[ l ],
2903 goto return_results;
2909 * trim the last ', ' (the allocated memory
2910 * is two bytes longer than required)
2912 ( *str )[ len - 2 ] = '\0';
2915 last_iRDN = iRDN - 1;
2917 for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
2919 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2921 if ( rdn2UFNstr( rdn, &( *str )[ l ],
2925 goto return_results;
2930 if ( !dn2domain( dn, &( *str )[ l ], &last_iRDN ) ) {
2933 goto return_results;
2936 /* the string is correctly terminated by dn2domain */
2938 #endif /* DC_IN_UFN */
2944 case LDAP_DN_FORMAT_DCE:
2946 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2948 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2950 if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
2951 goto return_results;
2957 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2958 rc = LDAP_NO_MEMORY;
2962 for ( l = 0; iRDN--; ) {
2964 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2966 if ( rdn2DCEstr( rdn, &( *str )[ l ], flags,
2970 goto return_results;
2977 ( *str )[ len ] = '\0';
2982 case LDAP_DN_FORMAT_AD_CANONICAL: {
2985 * Sort of UFN for DCE DNs: a slash ('/') separated
2986 * global->local DN with no types; strictly speaking,
2987 * the naming context should be a domain, which is
2988 * written in DNS-style, e.g. dot-deparated.
2992 * "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
2996 * "microsoft.com/People/Bill,Gates"
2998 for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
3000 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3002 if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
3003 goto return_results;
3009 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3010 rc = LDAP_NO_MEMORY;
3015 if ( iRDN && dn2domain( dn, *str, &iRDN ) ) {
3016 for ( l = strlen( *str ); iRDN >= 0 ; iRDN-- ) {
3018 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3020 if ( rdn2ADstr( rdn, &( *str )[ l ],
3021 flags, &rdnl, 0 ) ) {
3024 goto return_results;
3033 * Strictly speaking, AD canonical requires
3034 * a DN to be in the form "..., dc=smtg",
3035 * i.e. terminated by a domain component
3037 if ( flags & LDAP_DN_PEDANTIC ) {
3040 rc = LDAP_INVALID_DN_SYNTAX;
3044 for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3046 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3048 if ( rdn2ADstr( rdn, &( *str )[ l ],
3049 flags, &rdnl, first ) ) {
3052 goto return_results;
3061 ( *str )[ len ] = '\0';
3068 return( LDAP_INVALID_DN_SYNTAX );
3072 Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2str(%s,%u)=%d\n", *str, flags, rc );