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>
18 #include <ac/socket.h>
19 #include <ac/string.h>
24 /* extension to UFN that turns trailing "dc=value" rdns in DNS style,
25 * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */
27 /* #define PRETTY_ESCAPE */
29 static int dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout );
31 /* from libraries/libldap/schema.c */
32 extern char * parse_numericoid(const char **sp, int *code, const int flags);
34 /* parsing/printing routines */
35 static int str2strval( const char *str, struct berval *val,
36 const char **next, unsigned flags, unsigned *retFlags );
37 static int DCE2strval( const char *str, struct berval *val,
38 const char **next, unsigned flags );
39 static int IA52strval( const char *str, struct berval *val,
40 const char **next, unsigned flags );
41 static int quotedIA52strval( const char *str, struct berval *val,
42 const char **next, unsigned flags );
43 static int hexstr2binval( const char *str, struct berval *val,
44 const char **next, unsigned flags );
45 static int hexstr2bin( const char *str, char *c );
46 static int byte2hexpair( const char *val, char *pair );
47 static int binval2hexstr( struct berval *val, char *str );
48 static int strval2strlen( struct berval *val, unsigned flags,
50 static int strval2str( struct berval *val, char *str, unsigned flags,
52 static int strval2IA5strlen( struct berval *val, unsigned flags,
54 static int strval2IA5str( struct berval *val, char *str, unsigned flags,
56 static int strval2DCEstrlen( struct berval *val, unsigned flags,
58 static int strval2DCEstr( struct berval *val, char *str, unsigned flags,
60 static int strval2ADstrlen( struct berval *val, unsigned flags,
62 static int strval2ADstr( struct berval *val, char *str, unsigned flags,
64 static int dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN );
67 static LDAPAVA * ldapava_new(
68 const struct berval *attr, const struct berval *val, unsigned flags );
69 static LDAPRDN * ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava );
70 static LDAPRDN * ldapava_insert_into_rdn(
71 LDAPRDN *rdn, LDAPAVA *ava, unsigned where );
72 static LDAPDN * ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn );
73 static LDAPDN * ldapava_insert_into_dn(
74 LDAPDN *dn, LDAPRDN *rdn, unsigned where );
76 /* Higher level helpers */
77 static int rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
78 int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
79 static int rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
80 int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
81 static int rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
82 static int rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len );
83 static int rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
84 static int rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flag, ber_len_t *len, int first );
85 static int rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
86 static int rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first );
89 * RFC 1823 ldap_get_dn
92 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
97 Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
99 if ( entry == NULL ) {
100 ld->ld_errno = LDAP_PARAM_ERROR;
104 tmp = *entry->lm_ber; /* struct copy */
105 if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
106 ld->ld_errno = LDAP_DECODING_ERROR;
114 * RFC 1823 ldap_dn2ufn
117 ldap_dn2ufn( LDAP_CONST char *dn )
121 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
123 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_UFN );
129 * RFC 1823 ldap_explode_dn
132 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
135 char **values = NULL;
137 unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
139 Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
141 if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP )
146 if( tmpDN == NULL ) {
147 values = LDAP_MALLOC( sizeof( char * ) );
148 if( values == NULL ) return NULL;
154 for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ );
156 values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iRDN ) );
157 if ( values == NULL ) {
158 ldap_dnfree( tmpDN );
162 for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) {
163 ldap_rdn2str( tmpDN[ iRDN ][ 0 ], &values[ iRDN ], flag );
165 ldap_dnfree( tmpDN );
166 values[ iRDN ] = NULL;
172 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
175 char **values = NULL;
179 Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
182 * we only parse the first rdn
183 * FIXME: we prefer efficiency over checking if the _ENTIRE_
186 if ( ldap_str2rdn( rdn, &tmpRDN, &p, LDAP_DN_FORMAT_LDAP )
191 for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) ;
192 values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iAVA ) );
193 if ( values == NULL ) {
194 ldap_rdnfree( tmpRDN );
198 for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) {
199 ber_len_t l = 0, vl, al = 0;
201 LDAPAVA *ava = tmpRDN[ iAVA ][ 0 ];
203 if ( ava->la_flags == LDAP_AVA_BINARY ) {
204 vl = 1 + 2 * ava->la_value.bv_len;
207 if ( strval2strlen( &ava->la_value,
208 ava->la_flags, &vl ) ) {
214 al = ava->la_attr.bv_len;
215 l = vl + ava->la_attr.bv_len + 1;
217 str = LDAP_MALLOC( l + 1 );
218 AC_MEMCPY( str, ava->la_attr.bv_val,
219 ava->la_attr.bv_len );
224 str = LDAP_MALLOC( l + 1 );
227 if ( ava->la_flags == LDAP_AVA_BINARY ) {
229 if ( binval2hexstr( &ava->la_value, &str[ al ] ) ) {
234 if ( strval2str( &ava->la_value, &str[ al ],
235 ava->la_flags, &vl ) ) {
241 values[ iAVA ] = str;
243 values[ iAVA ] = NULL;
245 ldap_rdnfree( tmpRDN );
250 LBER_VFREE( values );
251 ldap_rdnfree( tmpRDN );
256 ldap_dn2dcedn( LDAP_CONST char *dn )
260 Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
262 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_DCE );
268 ldap_dcedn2dn( LDAP_CONST char *dce )
272 Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
274 ( void )dn2dn( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
280 ldap_dn2ad_canonical( LDAP_CONST char *dn )
284 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
286 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP,
287 &out, LDAP_DN_FORMAT_AD_CANONICAL );
293 ldap_dn_normalize( const char *in, unsigned iflags, char **out, unsigned oflags )
297 Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );
299 return dn2dn( in, iflags, out, oflags);
303 * helper that changes the string representation of dnin
304 * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
307 * LDAP_DN_FORMAT_LDAP (rfc 2253 and ldapbis liberal,
308 * plus some rfc 1779)
309 * LDAP_DN_FORMAT_LDAPV3 (rfc 2253 and ldapbis)
310 * LDAP_DN_FORMAT_LDAPV2 (rfc 1779)
311 * LDAP_DN_FORMAT_DCE (?)
313 * fout can be any of the above except
314 * LDAP_DN_FORMAT_LDAP
316 * LDAP_DN_FORMAT_UFN (rfc 1781, partial and with extensions)
317 * LDAP_DN_FORMAT_AD_CANONICAL (?)
320 dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout )
323 LDAPDN *tmpDN = NULL;
329 if ( dnin == NULL ) {
330 return( LDAP_SUCCESS );
333 rc = ldap_str2dn( dnin , &tmpDN, fin );
334 if ( rc != LDAP_SUCCESS ) {
338 rc = ldap_dn2str( tmpDN, dnout, fout );
340 ldap_dnfree( tmpDN );
348 /* #define B4ATTRTYPE 0x0001 */
349 #define B4OIDATTRTYPE 0x0002
350 #define B4STRINGATTRTYPE 0x0003
352 #define B4AVAEQUALS 0x0100
353 #define B4AVASEP 0x0200
354 #define B4RDNSEP 0x0300
355 #define GOTAVA 0x0400
357 #define B4ATTRVALUE 0x0010
358 #define B4STRINGVALUE 0x0020
359 #define B4IA5VALUEQUOTED 0x0030
360 #define B4IA5VALUE 0x0040
361 #define B4BINARYVALUE 0x0050
364 * Helpers (mostly from slap.h)
365 * c is assumed to Unicode in an ASCII compatible format (UTF-8)
366 * Macros assume "C" Locale (ASCII)
368 #define LDAP_DN_ASCII_SPACE(c) \
369 ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
370 #define LDAP_DN_ASCII_LOWER(c) ( (c) >= 'a' && (c) <= 'z' )
371 #define LDAP_DN_ASCII_UPPER(c) ( (c) >= 'A' && (c) <= 'Z' )
372 #define LDAP_DN_ASCII_ALPHA(c) \
373 ( LDAP_DN_ASCII_LOWER(c) || LDAP_DN_ASCII_UPPER(c) )
374 #define LDAP_DN_ASCII_DIGIT(c) ( (c) >= '0' && (c) <= '9' )
375 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) ( (c) >= 'a' && (c) <= 'f' )
376 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) ( (c) >= 'A' && (c) <= 'F' )
377 #define LDAP_DN_ASCII_HEXDIGIT(c) \
378 ( LDAP_DN_ASCII_DIGIT(c) \
379 || LDAP_DN_ASCII_LCASE_HEXALPHA(c) \
380 || LDAP_DN_ASCII_UCASE_HEXALPHA(c) )
381 #define LDAP_DN_ASCII_ALNUM(c) \
382 ( LDAP_DN_ASCII_ALPHA(c) || LDAP_DN_ASCII_DIGIT(c) )
383 #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' )
386 #define LDAP_DN_OID_LEADCHAR(c) ( LDAP_DN_ASCII_DIGIT(c) )
387 #define LDAP_DN_DESC_LEADCHAR(c) ( LDAP_DN_ASCII_ALPHA(c) )
388 #define LDAP_DN_DESC_CHAR(c) ( LDAP_DN_ASCII_ALNUM(c) || (c) == '-' )
389 #define LDAP_DN_LANG_SEP(c) ( (c) == ';' )
390 #define LDAP_DN_ATTRDESC_CHAR(c) \
391 ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
393 /* special symbols */
394 #define LDAP_DN_AVA_EQUALS(c) ( (c) == '=' )
395 #define LDAP_DN_AVA_SEP(c) ( (c) == '+' )
396 #define LDAP_DN_RDN_SEP(c) ( (c) == ',' )
397 #define LDAP_DN_RDN_SEP_V2(c) ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
398 #define LDAP_DN_OCTOTHORPE(c) ( (c) == '#' )
399 #define LDAP_DN_QUOTES(c) ( (c) == '\"' )
400 #define LDAP_DN_ESCAPE(c) ( (c) == '\\' )
401 #define LDAP_DN_VALUE_END(c) \
402 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
403 #define LDAP_DN_NE(c) \
404 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
405 || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
406 #define LDAP_DN_NEEDESCAPE(c) \
407 ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
408 #define LDAP_DN_NEEDESCAPE_LEAD(c) \
409 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) )
410 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
411 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
412 #define LDAP_DN_WILLESCAPE_CHAR(c) \
413 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) || LDAP_DN_ESCAPE(c) )
414 #define LDAP_DN_IS_PRETTY(f) ( (f) & LDAP_DN_PRETTY )
415 #define LDAP_DN_WILLESCAPE_HEX(f, c) \
416 ( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
419 #define LDAP_DN_VALUE_END_V2(c) \
420 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
422 #define LDAP_DN_V2_SPECIAL(c) \
423 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
424 || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
425 || LDAP_DN_OCTOTHORPE(c) )
426 #define LDAP_DN_V2_PAIR(c) \
427 ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
430 * DCE (mostly from Luke Howard and IBM implementation for AIX)
432 * From: "Application Development Guide - Directory Services" (FIXME: add link?)
433 * Here escapes and valid chars for GDS are considered; as soon as more
434 * specific info is found, the macros will be updated.
436 * Chars: 'a'-'z', 'A'-'Z', '0'-'9',
437 * '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
439 * Metachars: '/', ',', '=', '\'.
441 * the '\' is used to escape other metachars.
447 * Attribute types must start with alphabetic chars and can contain
448 * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
450 #define LDAP_DN_RDN_SEP_DCE(c) ( (c) == '/' )
451 #define LDAP_DN_AVA_SEP_DCE(c) ( (c) == ',' )
452 #define LDAP_DN_ESCAPE_DCE(c) ( LDAP_DN_ESCAPE(c) )
453 #define LDAP_DN_VALUE_END_DCE(c) \
454 ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
455 #define LDAP_DN_NEEDESCAPE_DCE(c) \
456 ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
459 #define LDAP_DN_RDN_SEP_AD(c) ( (c) == '/' )
460 #define LDAP_DN_ESCAPE_AD(c) ( LDAP_DN_ESCAPE(c) )
461 #define LDAP_DN_AVA_SEP_AD(c) ( (c) == ',' ) /* assume same as DCE */
462 #define LDAP_DN_VALUE_END_AD(c) \
463 ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
464 #define LDAP_DN_NEEDESCAPE_AD(c) \
465 ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
468 #define LDAP_DN_HEXPAIR(s) \
469 ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
470 /* better look at the AttributeDescription? */
472 /* FIXME: no composite rdn or non-"dc" types, right?
473 * (what about "dc" in OID form?) */
474 /* FIXME: we do not allow binary values in domain, right? */
475 /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
476 /* NOTE: don't use strcasecmp() as it is locale specific! */
477 #define LDAP_DC_ATTR "dc"
478 #define LDAP_DC_ATTRU "DC"
479 #define LDAP_DN_IS_RDN_DC( r ) \
480 ( (r) && (r)[0][0] && !(r)[1] \
481 && ((r)[0][0]->la_flags == LDAP_AVA_STRING) \
482 && ((r)[0][0]->la_attr.bv_len == 2) \
483 && (((r)[0][0]->la_attr.bv_val[0] == LDAP_DC_ATTR[0]) \
484 || ((r)[0][0]->la_attr.bv_val[0] == LDAP_DC_ATTRU[0])) \
485 && (((r)[0][0]->la_attr.bv_val[1] == LDAP_DC_ATTR[1]) \
486 || ((r)[0][0]->la_attr.bv_val[1] == LDAP_DC_ATTRU[1])))
488 /* Composite rules */
489 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
490 ( LDAP_DN_LDAPV2(f) \
491 || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
492 #define LDAP_DN_ALLOW_SPACES(f) \
493 ( LDAP_DN_LDAPV2(f) \
494 || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
495 #define LDAP_DN_LDAP(f) \
496 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
497 #define LDAP_DN_LDAPV3(f) \
498 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
499 #define LDAP_DN_LDAPV2(f) \
500 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
501 #define LDAP_DN_DCE(f) \
502 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
503 #define LDAP_DN_UFN(f) \
504 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
505 #define LDAP_DN_ADC(f) \
506 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
507 #define LDAP_DN_FORMAT(f) ( (f) & LDAP_DN_FORMAT_MASK )
510 * LDAPAVA helpers (will become part of the API for operations
511 * on structural representations of DNs).
514 ldapava_new( const struct berval *attr, const struct berval *val,
522 ava = LDAP_MALLOC( sizeof( LDAPAVA ) );
524 /* should we test it? */
529 ava->la_attr = *attr;
530 ava->la_value = *val;
531 ava->la_flags = flags;
533 ava->la_private = NULL;
539 ldap_avafree( LDAPAVA *ava )
544 /* ava's private must be freed by caller
545 * (at present let's skip this check because la_private
546 * basically holds static data) */
547 assert( ava->la_private == NULL );
550 free( ava->la_attr.bv_val );
551 free( ava->la_value.bv_val );
557 ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava )
565 for ( i = 0U; rdn[ i ]; i++ ) {
569 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
570 newRDN[ i ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
571 newRDN[ i ][ 0 ] = ava;
572 newRDN[ i + 1 ] = NULL;
578 ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where )
586 for ( i = 0U; rdn[ i ]; i++ ) {
592 /* assume "at end", which corresponds to
593 * ldapava_append_to_rdn */
596 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
598 /* data after insert point */
599 AC_MEMCPY( &newRDN[ where + 1 ], &newRDN[ where ],
600 ( i - where ) * sizeof( LDAPRDN * ) );
602 newRDN[ where ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
603 newRDN[ where ][ 0 ] = ava;
604 newRDN[ i + 1 ] = NULL;
610 ldap_rdnfree( LDAPRDN *rdn )
618 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
619 assert( rdn[ iAVA ][ 0 ] );
621 ldap_avafree( rdn[ iAVA ][ 0 ] );
628 ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn )
636 for ( i = 0U; dn[ i ]; i++ ) {
640 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
641 newDN[ i ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
642 newDN[ i ][ 0 ] = rdn;
643 newDN[ i + 1 ] = NULL;
649 ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where )
657 for ( i = 0U; dn[ i ]; i++ ) {
663 /* assume "at end", which corresponds to
664 * ldapava_append_to_dn */
667 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
669 /* data after insert point */
670 AC_MEMCPY( &newDN[ where + 1 ], &newDN[ where ],
671 ( i - where ) * sizeof( LDAPDN * ) );
673 newDN[ where ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
674 newDN[ where ][ 0 ] = rdn;
675 newDN[ i + 1 ] = NULL;
681 ldap_dnfree( LDAPDN *dn )
689 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
690 assert( dn[ iRDN ][ 0 ] );
692 ldap_rdnfree( dn[ iRDN ][ 0 ] );
699 * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
700 * into a structural representation of the DN, by separating attribute
701 * types and values encoded in the more appropriate form, which is
702 * string or OID for attribute types and binary form of the BER encoded
703 * value or Unicode string. Formats different from LDAPv3 are parsed
704 * according to their own rules and turned into the more appropriate
705 * form according to LDAPv3.
707 * NOTE: I realize the code is getting spaghettish; it is rather
708 * experimental and will hopefully turn into something more simple
709 * and readable as soon as it works as expected.
713 ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
716 int rc = LDAP_INVALID_DN_SYNTAX;
718 LDAPDN *newDN = NULL;
719 LDAPRDN *newRDN = NULL;
724 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );
728 switch ( LDAP_DN_FORMAT( flags ) ) {
729 case LDAP_DN_FORMAT_LDAP:
730 case LDAP_DN_FORMAT_LDAPV3:
731 case LDAP_DN_FORMAT_LDAPV2:
732 case LDAP_DN_FORMAT_DCE:
735 /* unsupported in str2dn */
736 case LDAP_DN_FORMAT_UFN:
737 case LDAP_DN_FORMAT_AD_CANONICAL:
738 return( LDAP_INVALID_DN_SYNTAX );
741 return( LDAP_OTHER );
744 if ( str[ 0 ] == '\0' ) {
745 return( LDAP_SUCCESS );
749 if ( LDAP_DN_DCE( flags ) ) {
752 * (from Luke Howard: thnx) A RDN separator is required
753 * at the beginning of an (absolute) DN.
755 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
760 } else if ( LDAP_DN_LDAP( flags ) ) {
762 * if dn starts with '/' let's make it a DCE dn
764 if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
765 flags |= LDAP_DN_FORMAT_DCE;
770 for ( ; p[ 0 ]; p++ ) {
774 err = ldap_str2rdn( p, &newRDN, &p, flags );
775 if ( err != LDAP_SUCCESS ) {
780 * We expect a rdn separator
783 switch ( LDAP_DN_FORMAT( flags ) ) {
784 case LDAP_DN_FORMAT_LDAPV3:
785 if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
791 case LDAP_DN_FORMAT_LDAP:
792 case LDAP_DN_FORMAT_LDAPV2:
793 if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
799 case LDAP_DN_FORMAT_DCE:
800 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
809 if ( LDAP_DN_DCE( flags ) ) {
810 /* add in reversed order */
811 dn = ldapava_insert_into_dn( newDN, newRDN, 0 );
813 dn = ldapava_append_to_dn( newDN, newRDN );
824 if ( p[ 0 ] == '\0' ) {
827 * the DN is over, phew
836 ldap_rdnfree( newRDN );
840 ldap_dnfree( newDN );
846 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
855 * Parses a relative DN according to flags up to a rdn separator
856 * or to the end of str.
857 * Returns the rdn and a pointer to the string continuation, which
858 * corresponds to the rdn separator or to '\0' in case the string is over.
861 ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
865 int rc = LDAP_INVALID_DN_SYNTAX;
866 int attrTypeEncoding = LDAP_AVA_STRING,
867 attrValueEncoding = LDAP_AVA_STRING;
869 struct berval attrType = { 0, NULL };
870 struct berval attrValue = { 0, NULL };
872 LDAPRDN *newRDN = NULL;
875 assert( rdn || flags & LDAP_DN_SKIP );
878 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );
885 switch ( LDAP_DN_FORMAT( flags ) ) {
886 case LDAP_DN_FORMAT_LDAP:
887 case LDAP_DN_FORMAT_LDAPV3:
888 case LDAP_DN_FORMAT_LDAPV2:
889 case LDAP_DN_FORMAT_DCE:
892 /* unsupported in str2dn */
893 case LDAP_DN_FORMAT_UFN:
894 case LDAP_DN_FORMAT_AD_CANONICAL:
895 return( LDAP_INVALID_DN_SYNTAX );
898 return( LDAP_OTHER );
901 if ( str[ 0 ] == '\0' ) {
902 return( LDAP_SUCCESS );
906 for ( ; p[ 0 ] || state == GOTAVA; ) {
909 * The parser in principle advances one token a time,
910 * or toggles state if preferable.
915 * an AttributeType can be encoded as:
916 * - its string representation; in detail, implementations
917 * MUST recognize AttributeType string type names listed
918 * in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
919 * MAY recognize other names.
920 * - its numeric OID (a dotted decimal string); in detail
921 * RFC 2253 asserts that ``Implementations MUST allow
922 * an oid in the attribute type to be prefixed by one
923 * of the character strings "oid." or "OID."''. As soon
924 * as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253
925 * I'm not sure whether this is required or not any
926 * longer; to be liberal, we still implement it.
929 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
930 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
937 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
938 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
943 /* whitespace is allowed (and trimmed) */
945 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
950 /* error: we expected an AVA */
956 if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
957 state = B4OIDATTRTYPE;
961 /* else must be alpha */
962 if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
966 /* LDAPv2 "oid." prefix */
967 if ( LDAP_DN_LDAPV2( flags ) ) {
969 * to be overly pedantic, we only accept
972 if ( flags & LDAP_DN_PEDANTIC ) {
973 if ( !strncmp( p, "OID.", 4 )
974 || !strncmp( p, "oid.", 4 ) ) {
976 state = B4OIDATTRTYPE;
980 if ( !strncasecmp( p, "oid.", 4 ) ) {
982 state = B4OIDATTRTYPE;
988 state = B4STRINGATTRTYPE;
991 case B4OIDATTRTYPE: {
992 int err = LDAP_SUCCESS;
995 type = parse_numericoid( &p, &err, 0 );
996 if ( type == NULL ) {
1000 if ( flags & LDAP_DN_SKIP ) {
1002 * FIXME: hack for skipping a rdn;
1003 * need a cleaner solution
1008 ber_str2bv( type, 0, 0, &attrType );
1011 attrTypeEncoding = LDAP_AVA_BINARY;
1013 state = B4AVAEQUALS;
1017 case B4STRINGATTRTYPE: {
1018 const char *startPos, *endPos = NULL;
1022 * the starting char has been found to be
1023 * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
1024 * FIXME: DCE attr types seem to have a more
1025 * restrictive syntax (no '-' ...)
1027 for ( startPos = p++; p[ 0 ]; p++ ) {
1028 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
1032 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
1035 * RFC 2253 does not explicitly
1036 * allow lang extensions to attribute
1039 if ( flags & LDAP_DN_PEDANTIC ) {
1044 * we trim ';' and following lang
1045 * and so from attribute types
1048 for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
1049 || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
1057 len = ( endPos ? endPos : p ) - startPos;
1062 attrTypeEncoding = LDAP_AVA_STRING;
1065 * here we need to decide whether to use it as is
1066 * or turn it in OID form; as a consequence, we
1067 * need to decide whether to binary encode the value
1070 state = B4AVAEQUALS;
1072 if ( flags & LDAP_DN_SKIP ) {
1076 attrType.bv_val = LDAP_STRNDUP( startPos, len );
1077 if ( attrType.bv_val == NULL ) {
1078 rc = LDAP_NO_MEMORY;
1081 attrType.bv_len = len;
1087 /* spaces may not be allowed */
1088 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1089 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1094 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1099 /* need equal sign */
1100 if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1105 /* spaces may not be allowed */
1106 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1107 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1112 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1118 * octothorpe means a BER encoded value will follow
1119 * FIXME: I don't think DCE will allow it
1121 if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1123 attrValueEncoding = LDAP_AVA_BINARY;
1124 state = B4BINARYVALUE;
1128 /* STRING value expected */
1131 * if we're pedantic, an attribute type in OID form
1132 * SHOULD imply a BER encoded attribute value; we
1133 * should at least issue a warning
1135 if ( ( flags & LDAP_DN_PEDANTIC )
1136 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1137 /* OID attrType SHOULD use binary encoding */
1141 attrValueEncoding = LDAP_AVA_STRING;
1144 * LDAPv2 allows the attribute value to be quoted;
1145 * also, IA5 values are expected, in principle
1147 if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1148 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1150 state = B4IA5VALUEQUOTED;
1154 if ( LDAP_DN_LDAPV2( flags ) ) {
1161 * here STRING means RFC 2253 string
1162 * FIXME: what about DCE strings?
1164 state = B4STRINGVALUE;
1168 if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
1176 switch ( LDAP_DN_FORMAT( flags ) ) {
1177 case LDAP_DN_FORMAT_LDAP:
1178 case LDAP_DN_FORMAT_LDAPV3:
1179 if ( str2strval( p, &attrValue, &p, flags,
1180 &attrValueEncoding ) ) {
1185 case LDAP_DN_FORMAT_DCE:
1186 if ( DCE2strval( p, &attrValue, &p, flags ) ) {
1199 if ( IA52strval( p, &attrValue, &p, flags ) ) {
1206 case B4IA5VALUEQUOTED:
1208 /* lead quote already stripped */
1209 if ( quotedIA52strval( p, &attrValue,
1220 if ( !( flags & LDAP_DN_SKIP ) ) {
1225 * we accept empty values
1227 ava = ldapava_new( &attrType, &attrValue,
1228 attrValueEncoding );
1229 if ( ava == NULL ) {
1230 rc = LDAP_NO_MEMORY;
1234 rdn = ldapava_append_to_rdn( newRDN, ava );
1235 if ( rdn == NULL ) {
1236 rc = LDAP_NO_MEMORY;
1243 * if we got an AVA separator ('+', or ',' for DCE )
1244 * we expect a new AVA for this RDN; otherwise
1245 * we add the RDN to the DN
1247 switch ( LDAP_DN_FORMAT( flags ) ) {
1248 case LDAP_DN_FORMAT_LDAP:
1249 case LDAP_DN_FORMAT_LDAPV3:
1250 case LDAP_DN_FORMAT_LDAPV2:
1251 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1256 case LDAP_DN_FORMAT_DCE:
1257 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1265 * the RDN is over, phew
1272 /* they should have been used in an AVA */
1273 attrType.bv_val = NULL;
1274 attrValue.bv_val = NULL;
1288 /* They are set to NULL after they're used in an AVA */
1289 if ( attrType.bv_val ) {
1290 free( attrType.bv_val );
1293 if ( attrValue.bv_val ) {
1294 free( attrValue.bv_val );
1298 ldap_rdnfree( newRDN );
1304 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n",
1314 * reads in a UTF-8 string value, unescaping stuff:
1315 * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1316 * '\' + HEXPAIR(p) -> unhex(p)
1319 str2strval( const char *str, struct berval *val, const char **next, unsigned flags, unsigned *retFlags )
1321 const char *p, *startPos, *endPos = NULL;
1322 ber_len_t len, escapes, unescapes;
1330 for ( startPos = p = str, escapes = 0, unescapes = 0; p[ 0 ]; p++ ) {
1331 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1333 if ( p[ 0 ] == '\0' ) {
1336 if ( ( p == startPos + 1 && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1337 || ( LDAP_DN_VALUE_END( p[ 1 ] ) && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
1338 || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1343 if ( LDAP_DN_HEXPAIR( p ) ) {
1346 hexstr2bin( p, &c );
1349 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1352 * we assume the string is UTF-8
1354 *retFlags = LDAP_AVA_NONPRINTABLE;
1361 if ( LDAP_DN_PEDANTIC & flags ) {
1365 * FIXME: we allow escaping
1366 * of chars that don't need
1367 * to and do not belong to
1368 * HEXDIGITS (we also allow
1369 * single hexdigit; maybe we
1374 } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) )
1375 || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1378 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1380 * FIXME: maybe we can add
1381 * escapes if not pedantic?
1388 * we do allow unescaped spaces at the end
1389 * of the value only in non-pedantic mode
1391 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1392 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1393 if ( flags & LDAP_DN_PEDANTIC ) {
1397 /* strip trailing (unescaped) spaces */
1398 for ( endPos = p - 1;
1399 endPos > startPos + 1 &&
1400 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1401 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1408 if ( flags & LDAP_DN_SKIP ) {
1413 * FIXME: test memory?
1415 len = ( endPos ? endPos : p ) - startPos - escapes - unescapes;
1418 if ( escapes == 0 && unescapes == 0 ) {
1419 val->bv_val = LDAP_STRNDUP( startPos, len );
1424 val->bv_val = LDAP_MALLOC( len + 1 );
1425 for ( s = 0, d = 0; d < len; ) {
1426 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1428 if ( ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( startPos[ s ] ) )
1429 || ( s == len - 1 && LDAP_DN_NEEDESCAPE_TRAIL( startPos[ s ] ) )
1430 || LDAP_DN_NEEDESCAPE( startPos[ s ] ) ) {
1431 val->bv_val[ d++ ] =
1434 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1437 hexstr2bin( &startPos[ s ], &c );
1438 val->bv_val[ d++ ] = c;
1443 * we allow escaping of chars
1444 * that do not need to
1446 val->bv_val[ d++ ] =
1451 val->bv_val[ d++ ] = startPos[ s++ ];
1455 val->bv_val[ d ] = '\0';
1456 assert( strlen( val->bv_val ) == len );
1463 DCE2strval( const char *str, struct berval *val, const char **next, unsigned flags )
1465 const char *p, *startPos, *endPos = NULL;
1466 ber_len_t len, escapes;
1474 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1475 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1477 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1484 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1489 * FIXME: can we accept anything else? I guess we need
1490 * to stop if a value is not legal
1495 * (unescaped) trailing spaces are trimmed must be silently ignored;
1498 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1499 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1500 if ( flags & LDAP_DN_PEDANTIC ) {
1504 /* strip trailing (unescaped) spaces */
1505 for ( endPos = p - 1;
1506 endPos > startPos + 1 &&
1507 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1508 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1515 if ( flags & LDAP_DN_SKIP ) {
1519 len = ( endPos ? endPos : p ) - startPos - escapes;
1521 if ( escapes == 0 ){
1522 val->bv_val = LDAP_STRNDUP( startPos, len );
1527 val->bv_val = LDAP_MALLOC( len + 1 );
1528 for ( s = 0, d = 0; d < len; ) {
1530 * This point is reached only if escapes
1531 * are properly used, so all we need to
1534 if ( LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1538 val->bv_val[ d++ ] = startPos[ s++ ];
1540 val->bv_val[ d ] = '\0';
1541 assert( strlen( val->bv_val ) == len );
1548 IA52strval( const char *str, struct berval *val, const char **next, unsigned flags )
1550 const char *p, *startPos, *endPos = NULL;
1551 ber_len_t len, escapes;
1563 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1564 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1566 if ( p[ 0 ] == '\0' ) {
1570 if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1571 && ( LDAP_DN_PEDANTIC & flags ) ) {
1576 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1581 * FIXME: can we accept anything else? I guess we need
1582 * to stop if a value is not legal
1586 /* strip trailing (unescaped) spaces */
1588 endPos > startPos + 1 &&
1589 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1590 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1596 if ( flags & LDAP_DN_SKIP ) {
1600 len = ( endPos ? endPos : p ) - startPos - escapes;
1602 if ( escapes == 0 ) {
1603 val->bv_val = LDAP_STRNDUP( startPos, len );
1608 val->bv_val = LDAP_MALLOC( len + 1 );
1609 for ( s = 0, d = 0; d < len; ) {
1610 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1613 val->bv_val[ d++ ] = startPos[ s++ ];
1615 val->bv_val[ d ] = '\0';
1616 assert( strlen( val->bv_val ) == len );
1623 quotedIA52strval( const char *str, struct berval *val, const char **next, unsigned flags )
1625 const char *p, *startPos, *endPos = NULL;
1627 unsigned escapes = 0;
1635 /* initial quote already eaten */
1636 for ( startPos = p = str; p[ 0 ]; p++ ) {
1638 * According to RFC 1779, the quoted value can
1639 * contain escaped as well as unescaped special values;
1640 * as a consequence we tolerate escaped values
1641 * (e.g. '"\,"' -> '\,') and escape unescaped specials
1642 * (e.g. '","' -> '\,').
1644 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1645 if ( p[ 1 ] == '\0' ) {
1650 if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1651 && ( LDAP_DN_PEDANTIC & flags ) ) {
1653 * do we allow to escape normal chars?
1654 * LDAPv2 does not allow any mechanism
1655 * for escaping chars with '\' and hex
1662 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1664 /* eat closing quotes */
1670 * FIXME: can we accept anything else? I guess we need
1671 * to stop if a value is not legal
1675 if ( endPos == NULL ) {
1679 /* Strip trailing (unescaped) spaces */
1680 for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1685 if ( flags & LDAP_DN_SKIP ) {
1689 len = endPos - startPos - escapes;
1692 if ( escapes == 0 ) {
1693 val->bv_val = LDAP_STRNDUP( startPos, len );
1698 val->bv_val = LDAP_MALLOC( len + 1 );
1701 for ( s = d = 0; d < len; ) {
1702 if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1705 val->bv_val[ d++ ] = str[ s++ ];
1707 val->bv_val[ d ] = '\0';
1708 assert( strlen( val->bv_val ) == len );
1715 hexstr2bin( const char *str, char *c )
1725 if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1729 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c1 ) ) {
1732 assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) );
1739 if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1743 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c2 ) ) {
1744 *c += c2 - 'A' + 10;
1746 assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) );
1747 *c += c2 - 'a' + 10;
1755 hexstr2binval( const char *str, struct berval *val, const char **next, unsigned flags )
1757 const char *p, *startPos, *endPos = NULL;
1767 for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1768 switch ( LDAP_DN_FORMAT( flags ) ) {
1769 case LDAP_DN_FORMAT_LDAPV3:
1770 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1775 case LDAP_DN_FORMAT_LDAP:
1776 case LDAP_DN_FORMAT_LDAPV2:
1777 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1782 case LDAP_DN_FORMAT_DCE:
1783 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1789 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1790 if ( flags & LDAP_DN_PEDANTIC ) {
1795 for ( ; p[ 0 ]; p++ ) {
1796 switch ( LDAP_DN_FORMAT( flags ) ) {
1797 case LDAP_DN_FORMAT_LDAPV3:
1798 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1803 case LDAP_DN_FORMAT_LDAP:
1804 case LDAP_DN_FORMAT_LDAPV2:
1805 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1810 case LDAP_DN_FORMAT_DCE:
1811 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1820 if ( !LDAP_DN_HEXPAIR( p ) ) {
1828 if ( flags & LDAP_DN_SKIP ) {
1832 len = ( ( endPos ? endPos : p ) - startPos ) / 2;
1834 assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
1837 val->bv_val = LDAP_MALLOC( len + 1 );
1838 if ( val->bv_val == NULL ) {
1839 return( LDAP_NO_MEMORY );
1842 for ( s = 0, d = 0; d < len; s += 2, d++ ) {
1845 hexstr2bin( &startPos[ s ], &c );
1847 val->bv_val[ d ] = c;
1850 val->bv_val[ d ] = '\0';
1856 * convert a byte in a hexadecimal pair
1859 byte2hexpair( const char *val, char *pair )
1861 static const char hexdig[] = "0123456789ABCDEF";
1867 * we assume the string has enough room for the hex encoding
1871 pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
1872 pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
1878 * convert a binary value in hexadecimal pairs
1881 binval2hexstr( struct berval *val, char *str )
1888 if ( val->bv_len == 0 ) {
1893 * we assume the string has enough room for the hex encoding
1897 for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
1898 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1905 * Length of the string representation, accounting for escaped hex
1909 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
1911 ber_len_t l, cl = 1;
1913 int escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3;
1914 #ifdef PRETTY_ESCAPE
1915 int escaped_ascii_len = LDAP_DN_IS_PRETTY( flags ) ? 2 : 3;
1916 #endif /* PRETTY_ESCAPE */
1922 if ( val->bv_len == 0 ) {
1926 for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
1927 cl = LDAP_UTF8_CHARLEN( p );
1929 /* illegal utf-8 char! */
1932 } else if ( cl > 1 ) {
1935 for ( cnt = 1; cnt < cl; cnt++ ) {
1936 if ( ( p[ cnt ] & 0x80 ) == 0x00 ) {
1940 l += escaped_byte_len * cl;
1942 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
1943 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1944 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
1945 #ifdef PRETTY_ESCAPE
1946 if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) {
1949 * there might be some chars we want
1950 * to escape in form of a couple
1951 * of hexdigits for optimization purposes
1956 l += escaped_ascii_len;
1958 #else /* ! PRETTY_ESCAPE */
1960 #endif /* ! PRETTY_ESCAPE */
1973 * convert to string representation, escaping with hex the UTF-8 stuff;
1974 * assume the destination has enough room for escaping
1977 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
1979 ber_len_t s, d, end;
1985 if ( val->bv_len == 0 ) {
1991 * we assume the string has enough room for the hex encoding
1994 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
1995 ber_len_t cl = LDAP_UTF8_CHARLEN( &val->bv_val[ s ] );
1998 * there might be some chars we want to escape in form
1999 * of a couple of hexdigits for optimization purposes
2001 if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) )
2002 #ifdef PRETTY_ESCAPE
2003 || LDAP_DN_WILLESCAPE_HEX( flags, val->bv_val[ s ] )
2004 #else /* ! PRETTY_ESCAPE */
2005 || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2006 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2007 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
2009 #endif /* ! PRETTY_ESCAPE */
2013 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2018 } else if ( cl > 1 ) {
2020 str[ d++ ] = val->bv_val[ s++ ];
2024 #ifdef PRETTY_ESCAPE
2025 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2026 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2027 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2029 if ( !LDAP_DN_IS_PRETTY( flags ) ) {
2030 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2036 #endif /* PRETTY_ESCAPE */
2037 str[ d++ ] = val->bv_val[ s++ ];
2047 * Length of the IA5 string representation (no UTF-8 allowed)
2050 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
2059 if ( val->bv_len == 0 ) {
2063 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2065 * Turn value into a binary encoded BER
2070 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2071 if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2072 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2073 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2088 * convert to string representation (np UTF-8)
2089 * assume the destination has enough room for escaping
2092 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2094 ber_len_t s, d, end;
2100 if ( val->bv_len == 0 ) {
2105 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2107 * Turn value into a binary encoded BER
2114 * we assume the string has enough room for the hex encoding
2118 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2119 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2120 || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2121 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2124 str[ d++ ] = val->bv_val[ s++ ];
2134 * Length of the (supposedly) DCE string representation,
2135 * accounting for escaped hex of UTF-8 chars
2138 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2147 if ( val->bv_len == 0 ) {
2151 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2153 * FIXME: Turn the value into a binary encoded BER?
2158 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2159 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2174 * convert to (supposedly) DCE string representation,
2175 * escaping with hex the UTF-8 stuff;
2176 * assume the destination has enough room for escaping
2179 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2187 if ( val->bv_len == 0 ) {
2192 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2194 * FIXME: Turn the value into a binary encoded BER?
2202 * we assume the string has enough room for the hex encoding
2206 for ( s = 0, d = 0; s < val->bv_len; ) {
2207 if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2210 str[ d++ ] = val->bv_val[ s++ ];
2220 * Length of the (supposedly) AD canonical string representation,
2221 * accounting for escaped hex of UTF-8 chars
2224 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2233 if ( val->bv_len == 0 ) {
2237 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2239 * FIXME: Turn the value into a binary encoded BER?
2244 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2245 if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2260 * convert to (supposedly) AD string representation,
2261 * escaping with hex the UTF-8 stuff;
2262 * assume the destination has enough room for escaping
2265 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2273 if ( val->bv_len == 0 ) {
2278 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2280 * FIXME: Turn the value into a binary encoded BER?
2288 * we assume the string has enough room for the hex encoding
2292 for ( s = 0, d = 0; s < val->bv_len; ) {
2293 if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2296 str[ d++ ] = val->bv_val[ s++ ];
2306 * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2307 * the first part of the AD representation of the DN is written in DNS
2308 * form, i.e. dot separated domain name components (as suggested
2309 * by Luke Howard, http://www.padl.com/~lukeh)
2312 dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN )
2315 int domain = 0, first = 1;
2316 ber_len_t l = 1; /* we move the null also */
2319 /* we are guaranteed there's enough memory in str */
2325 assert( *iRDN >= 0 );
2327 str = bv->bv_val + pos;
2329 for ( i = *iRDN; i >= 0; i-- ) {
2333 assert( dn[ i ][ 0 ] );
2336 assert( rdn[ 0 ][ 0 ] );
2337 ava = rdn[ 0 ][ 0 ];
2339 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2347 AC_MEMCPY( str, ava->la_value.bv_val,
2348 ava->la_value.bv_len + 1);
2349 l += ava->la_value.bv_len;
2352 AC_MEMCPY( str + ava->la_value.bv_len + 1, bv->bv_val, l);
2353 AC_MEMCPY( str, ava->la_value.bv_val,
2354 ava->la_value.bv_len );
2355 str[ ava->la_value.bv_len ] = '.';
2356 l += ava->la_value.bv_len + 1;
2361 bv->bv_len = pos + l - 1;
2367 rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
2368 int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2375 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2376 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2378 /* len(type) + '=' + '+' | ',' */
2379 l += ava->la_attr.bv_len + 2;
2381 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2382 /* octothorpe + twice the length */
2383 l += 1 + 2 * ava->la_value.bv_len;
2387 unsigned f = flags | ava->la_flags;
2389 if ( ( *s2l )( &ava->la_value, f, &vl ) ) {
2402 rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
2403 int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2408 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2409 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2411 AC_MEMCPY( &str[ l ], ava->la_attr.bv_val,
2412 ava->la_attr.bv_len );
2413 l += ava->la_attr.bv_len;
2417 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2419 if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2422 l += 2 * ava->la_value.bv_len;
2426 unsigned f = flags | ava->la_flags;
2428 if ( ( *s2s )( &ava->la_value, &str[ l ], f, &vl ) ) {
2433 str[ l++ ] = ( rdn[ iAVA + 1 ] ? '+' : ',' );
2442 rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2449 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2450 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2452 /* len(type) + '=' + ',' | '/' */
2453 l += ava->la_attr.bv_len + 2;
2455 switch ( ava->la_flags ) {
2456 case LDAP_AVA_BINARY:
2457 /* octothorpe + twice the length */
2458 l += 1 + 2 * ava->la_value.bv_len;
2461 case LDAP_AVA_STRING: {
2463 unsigned f = flags | ava->la_flags;
2465 if ( strval2DCEstrlen( &ava->la_value, f, &vl ) ) {
2483 rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2488 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2489 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2494 str[ l++ ] = ( iAVA ? ',' : '/' );
2497 AC_MEMCPY( &str[ l ], ava->la_attr.bv_val,
2498 ava->la_attr.bv_len );
2499 l += ava->la_attr.bv_len;
2503 switch ( ava->la_flags ) {
2504 case LDAP_AVA_BINARY:
2506 if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2509 l += 2 * ava->la_value.bv_len;
2512 case LDAP_AVA_STRING: {
2514 unsigned f = flags | ava->la_flags;
2516 if ( strval2DCEstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2534 rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2544 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2545 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2548 l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
2550 /* FIXME: are binary values allowed in UFN? */
2551 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2552 /* octothorpe + twice the value */
2553 l += 1 + 2 * ava->la_value.bv_len;
2557 unsigned f = flags | ava->la_flags;
2559 if ( strval2strlen( &ava->la_value, f, &vl ) ) {
2572 rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
2577 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2578 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2580 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2582 if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2585 l += 2 * ava->la_value.bv_len;
2589 unsigned f = flags | ava->la_flags;
2591 if ( strval2str( &ava->la_value, &str[ l ], f, &vl ) ) {
2597 if ( rdn[ iAVA + 1 ]) {
2598 AC_MEMCPY( &str[ l ], " + ", 3 );
2602 AC_MEMCPY( &str[ l ], ", ", 2 );
2613 rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2623 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2624 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2629 /* FIXME: are binary values allowed in UFN? */
2630 switch ( ava->la_flags ) {
2631 case LDAP_AVA_BINARY:
2632 /* octothorpe + twice the value */
2633 l += 1 + 2 * ava->la_value.bv_len;
2636 case LDAP_AVA_STRING: {
2638 unsigned f = flags | ava->la_flags;
2640 if ( strval2ADstrlen( &ava->la_value, f, &vl ) ) {
2658 rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2663 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2664 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2669 str[ l++ ] = ( iAVA ? ',' : '/' );
2672 switch ( ava->la_flags ) {
2673 case LDAP_AVA_BINARY:
2675 if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2678 l += 2 * ava->la_value.bv_len;
2681 case LDAP_AVA_STRING: {
2683 unsigned f = flags | ava->la_flags;
2685 if ( strval2ADstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2705 * Returns in str a string representation of rdn based on flags.
2706 * There is some duplication of code between this and ldap_dn2str;
2707 * this is wanted to reduce the allocation of temporary buffers.
2710 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2717 rc = ldap_rdn2bv( rdn, &bv, flags );
2723 ldap_rdn2bv( LDAPRDN *rdn, struct berval *bv, unsigned flags )
2733 if ( rdn == NULL ) {
2734 bv->bv_val = LDAP_STRDUP( "" );
2735 return( LDAP_SUCCESS );
2739 * This routine wastes "back" bytes at the end of the string
2742 switch ( LDAP_DN_FORMAT( flags ) ) {
2743 case LDAP_DN_FORMAT_LDAPV3:
2744 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2745 return( LDAP_OTHER );
2749 case LDAP_DN_FORMAT_LDAPV2:
2750 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2751 return( LDAP_OTHER );
2755 case LDAP_DN_FORMAT_UFN:
2756 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2757 return( LDAP_OTHER );
2761 case LDAP_DN_FORMAT_DCE:
2762 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2763 return( LDAP_OTHER );
2767 case LDAP_DN_FORMAT_AD_CANONICAL:
2768 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2769 return( LDAP_OTHER );
2774 return( LDAP_INVALID_DN_SYNTAX );
2777 bv->bv_val = LDAP_MALLOC( l + 1 );
2779 switch ( LDAP_DN_FORMAT( flags ) ) {
2780 case LDAP_DN_FORMAT_LDAPV3:
2781 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2str );
2785 case LDAP_DN_FORMAT_LDAPV2:
2786 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2IA5str );
2790 case LDAP_DN_FORMAT_UFN:
2791 rc = rdn2UFNstr( rdn, bv->bv_val, flags, &l );
2795 case LDAP_DN_FORMAT_DCE:
2796 rc = rdn2DCEstr( rdn, bv->bv_val, flags, &l, 1 );
2800 case LDAP_DN_FORMAT_AD_CANONICAL:
2801 rc = rdn2ADstr( rdn, bv->bv_val, flags, &l, 1 );
2806 /* need at least one of the previous */
2807 return( LDAP_OTHER );
2811 ldap_memfree( bv->bv_val );
2812 return( LDAP_OTHER );
2815 bv->bv_len = l - back;
2816 bv->bv_val[ bv->bv_len ] = '\0';
2818 return( LDAP_SUCCESS );
2822 * Very bulk implementation; many optimizations can be performed
2823 * - a NULL dn results in an empty string ""
2826 * a) what do we do if a UTF-8 string must be converted in LDAPv2?
2827 * we must encode it in binary form ('#' + HEXPAIRs)
2828 * b) does DCE/AD support UTF-8?
2829 * no clue; don't think so.
2830 * c) what do we do when binary values must be converted in UTF/DCE/AD?
2831 * use binary encoded BER
2833 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
2840 rc = ldap_dn2bv( dn, &bv, flags );
2845 int ldap_dn2bv( LDAPDN *dn, struct berval *bv, unsigned flags )
2848 int rc = LDAP_OTHER;
2851 /* stringifying helpers for LDAPv3/LDAPv2 */
2852 int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2853 int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2860 Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2bv(%u)\n%s%s", flags, "", "" );
2863 * a null dn means an empty dn string
2864 * FIXME: better raise an error?
2867 bv->bv_val = LDAP_STRDUP( "" );
2868 return( LDAP_SUCCESS );
2871 switch ( LDAP_DN_FORMAT( flags ) ) {
2872 case LDAP_DN_FORMAT_LDAPV3:
2873 sv2l = strval2strlen;
2877 case LDAP_DN_FORMAT_LDAPV2:
2878 sv2l = strval2IA5strlen;
2879 sv2s = strval2IA5str;
2882 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2884 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2886 if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
2887 goto return_results;
2893 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2894 rc = LDAP_NO_MEMORY;
2898 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
2900 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2902 if ( rdn2str( rdn, &bv->bv_val[ l ], flags,
2904 LDAP_FREE( bv->bv_val );
2906 goto return_results;
2914 * trim the last ',' (the allocated memory
2915 * is one byte longer than required)
2917 bv->bv_len = len - 1;
2918 bv->bv_val[ bv->bv_len ] = '\0';
2923 case LDAP_DN_FORMAT_UFN: {
2926 * FIXME: quoting from RFC 1781:
2928 To take a distinguished name, and generate a name of this format with
2929 attribute types omitted, the following steps are followed.
2931 1. If the first attribute is of type CommonName, the type may be
2934 2. If the last attribute is of type Country, the type may be
2937 3. If the last attribute is of type Country, the last
2938 Organisation attribute may have the type omitted.
2940 4. All attributes of type OrganisationalUnit may have the type
2941 omitted, unless they are after an Organisation attribute or
2942 the first attribute is of type OrganisationalUnit.
2944 * this should be the pedantic implementation.
2946 * Here the standard implementation reflects
2947 * the one historically provided by OpenLDAP
2948 * (and UMIch, I presume), with the variant
2949 * of spaces and plusses (' + ') separating
2952 * A non-standard but nice implementation could
2953 * be to turn the final "dc" attributes into a
2954 * dot-separated domain.
2956 * Other improvements could involve the use of
2957 * friendly country names and so.
2960 int leftmost_dc = -1;
2962 #endif /* DC_IN_UFN */
2964 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2966 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2968 if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
2969 goto return_results;
2974 if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
2975 if ( leftmost_dc == -1 ) {
2981 #endif /* DC_IN_UFN */
2984 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2985 rc = LDAP_NO_MEMORY;
2990 if ( leftmost_dc == -1 ) {
2991 #endif /* DC_IN_UFN */
2992 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
2994 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2996 if ( rdn2UFNstr( rdn, &bv->bv_val[ l ],
2998 LDAP_FREE( bv->bv_val );
3000 goto return_results;
3006 * trim the last ', ' (the allocated memory
3007 * is two bytes longer than required)
3009 bv->bv_len = len - 2;
3010 bv->bv_val[ bv->bv_len ] = '\0';
3013 last_iRDN = iRDN - 1;
3015 for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
3017 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3019 if ( rdn2UFNstr( rdn, &bv->bv_val[ l ],
3021 LDAP_FREE( bv->bv_val );
3023 goto return_results;
3028 if ( !dn2domain( dn, bv, l, &last_iRDN ) ) {
3029 LDAP_FREE( bv->bv_val );
3031 goto return_results;
3034 /* the string is correctly terminated by dn2domain */
3036 #endif /* DC_IN_UFN */
3042 case LDAP_DN_FORMAT_DCE:
3044 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3046 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3048 if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
3049 goto return_results;
3055 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3056 rc = LDAP_NO_MEMORY;
3060 for ( l = 0; iRDN--; ) {
3062 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3064 if ( rdn2DCEstr( rdn, &bv->bv_val[ l ], flags,
3066 LDAP_FREE( bv->bv_val );
3068 goto return_results;
3076 bv->bv_val[ bv->bv_len ] = '\0';
3081 case LDAP_DN_FORMAT_AD_CANONICAL: {
3084 * Sort of UFN for DCE DNs: a slash ('/') separated
3085 * global->local DN with no types; strictly speaking,
3086 * the naming context should be a domain, which is
3087 * written in DNS-style, e.g. dot-deparated.
3091 * "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3095 * "microsoft.com/People/Bill,Gates"
3097 for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
3099 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3101 if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
3102 goto return_results;
3108 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3109 rc = LDAP_NO_MEMORY;
3114 if ( iRDN && dn2domain( dn, bv, 0, &iRDN ) ) {
3115 for ( l = bv->bv_len; iRDN >= 0 ; iRDN-- ) {
3117 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3119 if ( rdn2ADstr( rdn, &bv->bv_val[ l ],
3120 flags, &rdnl, 0 ) ) {
3121 LDAP_FREE( bv->bv_val );
3123 goto return_results;
3132 * Strictly speaking, AD canonical requires
3133 * a DN to be in the form "..., dc=smtg",
3134 * i.e. terminated by a domain component
3136 if ( flags & LDAP_DN_PEDANTIC ) {
3137 LDAP_FREE( bv->bv_val );
3139 rc = LDAP_INVALID_DN_SYNTAX;
3143 for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3145 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3147 if ( rdn2ADstr( rdn, &bv->bv_val[ l ],
3148 flags, &rdnl, first ) ) {
3149 LDAP_FREE( bv->bv_val );
3151 goto return_results;
3161 bv->bv_val[ bv->bv_len ] = '\0';
3168 return( LDAP_INVALID_DN_SYNTAX );
3172 Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2bv(%s,%u)=%d\n", bv->bv_val, flags, rc );