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++ ) {
155 char *str, **v = NULL;
157 ldap_rdn2str( tmpDN[ iRDN ][ 0 ], &str, flag );
159 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iRDN ) );
161 LBER_VFREE( values );
162 ldap_dnfree( tmpDN );
166 values[ iRDN ] = str;
169 values[ iRDN ] = NULL;
174 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
177 char **values = NULL;
181 Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
184 * we only parse the first rdn
185 * FIXME: we prefer efficiency over checking if the _ENTIRE_
188 if ( ldap_str2rdn( rdn, &tmpRDN, &p, LDAP_DN_FORMAT_LDAP )
193 for ( iAVA = 0; tmpRDN[ iAVA ]; iAVA++ ) {
194 ber_len_t l = 0, vl, al = 0;
195 char *str, **v = NULL;
196 LDAPAVA *ava = tmpRDN[ iAVA ][ 0 ];
198 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iAVA ) );
204 if ( ava->la_flags == LDAP_AVA_BINARY ) {
205 vl = 1 + 2 * ava->la_value->bv_len;
208 if ( strval2strlen( ava->la_value,
209 ava->la_flags, &vl ) ) {
215 al = ava->la_attr->bv_len;
216 l = vl + ava->la_attr->bv_len + 1;
218 str = LDAP_MALLOC( l + 1 );
219 AC_MEMCPY( str, ava->la_attr->bv_val,
220 ava->la_attr->bv_len );
225 str = LDAP_MALLOC( l + 1 );
228 if ( ava->la_flags == LDAP_AVA_BINARY ) {
230 if ( binval2hexstr( ava->la_value, &str[ al ] ) ) {
235 if ( strval2str( ava->la_value, &str[ al ],
236 ava->la_flags, &vl ) ) {
242 values[ iAVA ] = str;
244 values[ iAVA ] = NULL;
246 ldap_rdnfree( tmpRDN );
251 LBER_VFREE( values );
252 ldap_rdnfree( tmpRDN );
257 ldap_dn2dcedn( LDAP_CONST char *dn )
261 Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
263 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_DCE );
269 ldap_dcedn2dn( LDAP_CONST char *dce )
273 Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
275 ( void )dn2dn( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
281 ldap_dn2ad_canonical( LDAP_CONST char *dn )
285 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
287 ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP,
288 &out, LDAP_DN_FORMAT_AD_CANONICAL );
294 ldap_dn_normalize( const char *in, unsigned iflags, char **out, unsigned oflags )
298 Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );
300 return dn2dn( in, iflags, out, oflags);
304 * helper that changes the string representation of dnin
305 * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
308 * LDAP_DN_FORMAT_LDAP (rfc 2253 and ldapbis liberal,
309 * plus some rfc 1779)
310 * LDAP_DN_FORMAT_LDAPV3 (rfc 2253 and ldapbis)
311 * LDAP_DN_FORMAT_LDAPV2 (rfc 1779)
312 * LDAP_DN_FORMAT_DCE (?)
314 * fout can be any of the above except
315 * LDAP_DN_FORMAT_LDAP
317 * LDAP_DN_FORMAT_UFN (rfc 1781, partial and with extensions)
318 * LDAP_DN_FORMAT_AD_CANONICAL (?)
321 dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout )
324 LDAPDN *tmpDN = NULL;
330 if ( dnin == NULL ) {
331 return( LDAP_SUCCESS );
334 rc = ldap_str2dn( dnin , &tmpDN, fin );
335 if ( rc != LDAP_SUCCESS ) {
339 rc = ldap_dn2str( tmpDN, dnout, fout );
341 ldap_dnfree( tmpDN );
349 /* #define B4ATTRTYPE 0x0001 */
350 #define B4OIDATTRTYPE 0x0002
351 #define B4STRINGATTRTYPE 0x0003
353 #define B4AVAEQUALS 0x0100
354 #define B4AVASEP 0x0200
355 #define B4RDNSEP 0x0300
356 #define GOTAVA 0x0400
358 #define B4ATTRVALUE 0x0010
359 #define B4STRINGVALUE 0x0020
360 #define B4IA5VALUEQUOTED 0x0030
361 #define B4IA5VALUE 0x0040
362 #define B4BINARYVALUE 0x0050
365 * Helpers (mostly from slap.h)
366 * c is assumed to Unicode in an ASCII compatible format (UTF-8)
367 * Macros assume "C" Locale (ASCII)
369 #define LDAP_DN_ASCII_SPACE(c) \
370 ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
371 #define LDAP_DN_ASCII_LOWER(c) ( (c) >= 'a' && (c) <= 'z' )
372 #define LDAP_DN_ASCII_UPPER(c) ( (c) >= 'A' && (c) <= 'Z' )
373 #define LDAP_DN_ASCII_ALPHA(c) \
374 ( LDAP_DN_ASCII_LOWER(c) || LDAP_DN_ASCII_UPPER(c) )
375 #define LDAP_DN_ASCII_DIGIT(c) ( (c) >= '0' && (c) <= '9' )
376 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) ( (c) >= 'a' && (c) <= 'f' )
377 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) ( (c) >= 'A' && (c) <= 'F' )
378 #define LDAP_DN_ASCII_HEXDIGIT(c) \
379 ( LDAP_DN_ASCII_DIGIT(c) \
380 || LDAP_DN_ASCII_LCASE_HEXALPHA(c) \
381 || LDAP_DN_ASCII_UCASE_HEXALPHA(c) )
382 #define LDAP_DN_ASCII_ALNUM(c) \
383 ( LDAP_DN_ASCII_ALPHA(c) || LDAP_DN_ASCII_DIGIT(c) )
384 #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' )
387 #define LDAP_DN_OID_LEADCHAR(c) ( LDAP_DN_ASCII_DIGIT(c) )
388 #define LDAP_DN_DESC_LEADCHAR(c) ( LDAP_DN_ASCII_ALPHA(c) )
389 #define LDAP_DN_DESC_CHAR(c) ( LDAP_DN_ASCII_ALNUM(c) || (c) == '-' )
390 #define LDAP_DN_LANG_SEP(c) ( (c) == ';' )
391 #define LDAP_DN_ATTRDESC_CHAR(c) \
392 ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
394 /* special symbols */
395 #define LDAP_DN_AVA_EQUALS(c) ( (c) == '=' )
396 #define LDAP_DN_AVA_SEP(c) ( (c) == '+' )
397 #define LDAP_DN_RDN_SEP(c) ( (c) == ',' )
398 #define LDAP_DN_RDN_SEP_V2(c) ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
399 #define LDAP_DN_OCTOTHORPE(c) ( (c) == '#' )
400 #define LDAP_DN_QUOTES(c) ( (c) == '\"' )
401 #define LDAP_DN_ESCAPE(c) ( (c) == '\\' )
402 #define LDAP_DN_VALUE_END(c) \
403 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
404 #define LDAP_DN_NE(c) \
405 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
406 || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
407 #define LDAP_DN_NEEDESCAPE(c) \
408 ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
409 #define LDAP_DN_NEEDESCAPE_LEAD(c) \
410 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) )
411 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
412 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
413 #define LDAP_DN_WILLESCAPE_CHAR(c) \
414 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) || LDAP_DN_ESCAPE(c) )
415 #define LDAP_DN_IS_PRETTY(f) ( (f) & LDAP_DN_PRETTY )
416 #define LDAP_DN_WILLESCAPE_HEX(f, c) \
417 ( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
420 #define LDAP_DN_VALUE_END_V2(c) \
421 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
423 #define LDAP_DN_V2_SPECIAL(c) \
424 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
425 || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
426 || LDAP_DN_OCTOTHORPE(c) )
427 #define LDAP_DN_V2_PAIR(c) \
428 ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
431 * DCE (mostly from Luke Howard and IBM implementation for AIX)
433 * From: "Application Development Guide - Directory Services" (FIXME: add link?)
434 * Here escapes and valid chars for GDS are considered; as soon as more
435 * specific info is found, the macros will be updated.
437 * Chars: 'a'-'z', 'A'-'Z', '0'-'9',
438 * '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
440 * Metachars: '/', ',', '=', '\'.
442 * the '\' is used to escape other metachars.
448 * Attribute types must start with alphabetic chars and can contain
449 * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
451 #define LDAP_DN_RDN_SEP_DCE(c) ( (c) == '/' )
452 #define LDAP_DN_AVA_SEP_DCE(c) ( (c) == ',' )
453 #define LDAP_DN_ESCAPE_DCE(c) ( LDAP_DN_ESCAPE(c) )
454 #define LDAP_DN_VALUE_END_DCE(c) \
455 ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
456 #define LDAP_DN_NEEDESCAPE_DCE(c) \
457 ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
460 #define LDAP_DN_RDN_SEP_AD(c) ( (c) == '/' )
461 #define LDAP_DN_ESCAPE_AD(c) ( LDAP_DN_ESCAPE(c) )
462 #define LDAP_DN_AVA_SEP_AD(c) ( (c) == ',' ) /* assume same as DCE */
463 #define LDAP_DN_VALUE_END_AD(c) \
464 ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
465 #define LDAP_DN_NEEDESCAPE_AD(c) \
466 ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
469 #define LDAP_DN_HEXPAIR(s) \
470 ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
471 /* better look at the AttributeDescription? */
473 /* FIXME: no composite rdn or non-"dc" types, right?
474 * (what about "dc" in OID form?) */
475 /* FIXME: we do not allow binary values in domain, right? */
476 /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
477 /* NOTE: don't use strcasecmp() as it is locale specific! */
478 #define LDAP_DC_ATTR "dc"
479 #define LDAP_DC_ATTRU "DC"
480 #define LDAP_DN_IS_RDN_DC( r ) \
481 ( (r) && (r)[0][0] && !(r)[1] \
482 && ((r)[0][0]->la_flags == LDAP_AVA_STRING) \
483 && ((r)[0][0]->la_attr->bv_len == 2) \
484 && (((r)[0][0]->la_attr->bv_val[0] == LDAP_DC_ATTR[0]) \
485 || ((r)[0][0]->la_attr->bv_val[0] == LDAP_DC_ATTRU[0])) \
486 && (((r)[0][0]->la_attr->bv_val[1] == LDAP_DC_ATTR[1]) \
487 || ((r)[0][0]->la_attr->bv_val[1] == LDAP_DC_ATTRU[1])))
489 /* Composite rules */
490 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
491 ( LDAP_DN_LDAPV2(f) \
492 || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
493 #define LDAP_DN_ALLOW_SPACES(f) \
494 ( LDAP_DN_LDAPV2(f) \
495 || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
496 #define LDAP_DN_LDAP(f) \
497 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
498 #define LDAP_DN_LDAPV3(f) \
499 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
500 #define LDAP_DN_LDAPV2(f) \
501 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
502 #define LDAP_DN_DCE(f) \
503 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
504 #define LDAP_DN_UFN(f) \
505 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
506 #define LDAP_DN_ADC(f) \
507 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
508 #define LDAP_DN_FORMAT(f) ( (f) & LDAP_DN_FORMAT_MASK )
511 * LDAPAVA helpers (will become part of the API for operations
512 * on structural representations of DNs).
515 ldapava_new( const struct berval *attr, const struct berval *val,
523 ava = LDAP_MALLOC( sizeof( LDAPAVA ) );
525 /* should we test it? */
530 ava->la_attr = ( struct berval * )attr;
531 ava->la_value = ( struct berval * )val;
532 ava->la_flags = flags;
534 ava->la_private = NULL;
540 ldap_avafree( LDAPAVA *ava )
545 /* ava's private must be freed by caller
546 * (at present let's skip this check because la_private
547 * basically holds static data) */
548 assert( ava->la_private == NULL );
551 ber_bvfree( ava->la_attr );
552 ber_bvfree( ava->la_value );
558 ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava )
566 for ( i = 0U; rdn[ i ]; i++ ) {
570 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
571 newRDN[ i ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
572 newRDN[ i ][ 0 ] = ava;
573 newRDN[ i + 1 ] = NULL;
579 ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where )
587 for ( i = 0U; rdn[ i ]; i++ ) {
593 /* assume "at end", which corresponds to
594 * ldapava_append_to_rdn */
597 newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
599 /* data after insert point */
600 AC_MEMCPY( &newRDN[ where + 1 ], &newRDN[ where ],
601 ( i - where ) * sizeof( LDAPRDN * ) );
603 newRDN[ where ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
604 newRDN[ where ][ 0 ] = ava;
605 newRDN[ i + 1 ] = NULL;
611 ldap_rdnfree( LDAPRDN *rdn )
619 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
620 assert( rdn[ iAVA ][ 0 ] );
622 ldap_avafree( rdn[ iAVA ][ 0 ] );
629 ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn )
637 for ( i = 0U; dn[ i ]; i++ ) {
641 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
642 newDN[ i ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
643 newDN[ i ][ 0 ] = rdn;
644 newDN[ i + 1 ] = NULL;
650 ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where )
658 for ( i = 0U; dn[ i ]; i++ ) {
664 /* assume "at end", which corresponds to
665 * ldapava_append_to_dn */
668 newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
670 /* data after insert point */
671 AC_MEMCPY( &newDN[ where + 1 ], &newDN[ where ],
672 ( i - where ) * sizeof( LDAPDN * ) );
674 newDN[ where ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
675 newDN[ where ][ 0 ] = rdn;
676 newDN[ i + 1 ] = NULL;
682 ldap_dnfree( LDAPDN *dn )
690 for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
691 assert( dn[ iRDN ][ 0 ] );
693 ldap_rdnfree( dn[ iRDN ][ 0 ] );
700 * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
701 * into a structural representation of the DN, by separating attribute
702 * types and values encoded in the more appropriate form, which is
703 * string or OID for attribute types and binary form of the BER encoded
704 * value or Unicode string. Formats different from LDAPv3 are parsed
705 * according to their own rules and turned into the more appropriate
706 * form according to LDAPv3.
708 * NOTE: I realize the code is getting spaghettish; it is rather
709 * experimental and will hopefully turn into something more simple
710 * and readable as soon as it works as expected.
714 ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
717 int rc = LDAP_INVALID_DN_SYNTAX;
719 LDAPDN *newDN = NULL;
720 LDAPRDN *newRDN = NULL;
725 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );
729 switch ( LDAP_DN_FORMAT( flags ) ) {
730 case LDAP_DN_FORMAT_LDAP:
731 case LDAP_DN_FORMAT_LDAPV3:
732 case LDAP_DN_FORMAT_LDAPV2:
733 case LDAP_DN_FORMAT_DCE:
736 /* unsupported in str2dn */
737 case LDAP_DN_FORMAT_UFN:
738 case LDAP_DN_FORMAT_AD_CANONICAL:
739 return( LDAP_INVALID_DN_SYNTAX );
742 return( LDAP_OTHER );
745 if ( str[ 0 ] == '\0' ) {
746 return( LDAP_SUCCESS );
750 if ( LDAP_DN_DCE( flags ) ) {
753 * (from Luke Howard: thnx) A RDN separator is required
754 * at the beginning of an (absolute) DN.
756 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
761 } else if ( LDAP_DN_LDAP( flags ) ) {
763 * if dn starts with '/' let's make it a DCE dn
765 if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
766 flags |= LDAP_DN_FORMAT_DCE;
771 for ( ; p[ 0 ]; p++ ) {
775 err = ldap_str2rdn( p, &newRDN, &p, flags );
776 if ( err != LDAP_SUCCESS ) {
781 * We expect a rdn separator
784 switch ( LDAP_DN_FORMAT( flags ) ) {
785 case LDAP_DN_FORMAT_LDAPV3:
786 if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
792 case LDAP_DN_FORMAT_LDAP:
793 case LDAP_DN_FORMAT_LDAPV2:
794 if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
800 case LDAP_DN_FORMAT_DCE:
801 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
810 if ( LDAP_DN_DCE( flags ) ) {
811 /* add in reversed order */
812 dn = ldapava_insert_into_dn( newDN, newRDN, 0 );
814 dn = ldapava_append_to_dn( newDN, newRDN );
825 if ( p[ 0 ] == '\0' ) {
828 * the DN is over, phew
837 ldap_rdnfree( newRDN );
841 ldap_dnfree( newDN );
847 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
856 * Parses a relative DN according to flags up to a rdn separator
857 * or to the end of str.
858 * Returns the rdn and a pointer to the string continuation, which
859 * corresponds to the rdn separator or to '\0' in case the string is over.
862 ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
866 int rc = LDAP_INVALID_DN_SYNTAX;
867 int attrTypeEncoding = LDAP_AVA_STRING,
868 attrValueEncoding = LDAP_AVA_STRING;
870 struct berval *attrType = NULL;
871 struct berval *attrValue = NULL;
873 LDAPRDN *newRDN = NULL;
876 assert( rdn || flags & LDAP_DN_SKIP );
879 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );
886 switch ( LDAP_DN_FORMAT( flags ) ) {
887 case LDAP_DN_FORMAT_LDAP:
888 case LDAP_DN_FORMAT_LDAPV3:
889 case LDAP_DN_FORMAT_LDAPV2:
890 case LDAP_DN_FORMAT_DCE:
893 /* unsupported in str2dn */
894 case LDAP_DN_FORMAT_UFN:
895 case LDAP_DN_FORMAT_AD_CANONICAL:
896 return( LDAP_INVALID_DN_SYNTAX );
899 return( LDAP_OTHER );
902 if ( str[ 0 ] == '\0' ) {
903 return( LDAP_SUCCESS );
907 for ( ; p[ 0 ] || state == GOTAVA; ) {
910 * The parser in principle advances one token a time,
911 * or toggles state if preferable.
916 * an AttributeType can be encoded as:
917 * - its string representation; in detail, implementations
918 * MUST recognize AttributeType string type names listed
919 * in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
920 * MAY recognize other names.
921 * - its numeric OID (a dotted decimal string); in detail
922 * RFC 2253 asserts that ``Implementations MUST allow
923 * an oid in the attribute type to be prefixed by one
924 * of the character strings "oid." or "OID."''. As soon
925 * as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253
926 * I'm not sure whether this is required or not any
927 * longer; to be liberal, we still implement it.
930 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
931 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
938 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
939 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
944 /* whitespace is allowed (and trimmed) */
946 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
951 /* error: we expected an AVA */
957 if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
958 state = B4OIDATTRTYPE;
962 /* else must be alpha */
963 if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
967 /* LDAPv2 "oid." prefix */
968 if ( LDAP_DN_LDAPV2( flags ) ) {
970 * to be overly pedantic, we only accept
973 if ( flags & LDAP_DN_PEDANTIC ) {
974 if ( !strncmp( p, "OID.", 4 )
975 || !strncmp( p, "oid.", 4 ) ) {
977 state = B4OIDATTRTYPE;
981 if ( !strncasecmp( p, "oid.", 4 ) ) {
983 state = B4OIDATTRTYPE;
989 state = B4STRINGATTRTYPE;
992 case B4OIDATTRTYPE: {
993 int err = LDAP_SUCCESS;
996 type = parse_numericoid( &p, &err, 0 );
997 if ( type == NULL ) {
1001 if ( flags & LDAP_DN_SKIP ) {
1003 * FIXME: hack for skipping a rdn;
1004 * need a cleaner solution
1009 attrType = ber_bvstr( type );
1010 if ( attrType == NULL ) {
1011 rc = LDAP_NO_MEMORY;
1016 attrTypeEncoding = LDAP_AVA_BINARY;
1018 state = B4AVAEQUALS;
1022 case B4STRINGATTRTYPE: {
1023 const char *startPos, *endPos = NULL;
1027 * the starting char has been found to be
1028 * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
1029 * FIXME: DCE attr types seem to have a more
1030 * restrictive syntax (no '-' ...)
1032 for ( startPos = p++; p[ 0 ]; p++ ) {
1033 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
1037 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
1040 * RFC 2253 does not explicitly
1041 * allow lang extensions to attribute
1044 if ( flags & LDAP_DN_PEDANTIC ) {
1049 * we trim ';' and following lang
1050 * and so from attribute types
1053 for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
1054 || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
1062 len = ( endPos ? endPos : p ) - startPos;
1067 attrTypeEncoding = LDAP_AVA_STRING;
1070 * here we need to decide whether to use it as is
1071 * or turn it in OID form; as a consequence, we
1072 * need to decide whether to binary encode the value
1075 state = B4AVAEQUALS;
1077 if ( flags & LDAP_DN_SKIP ) {
1081 assert( attrType == NULL );
1082 attrType = LDAP_MALLOC( sizeof( struct berval ) );
1083 if ( attrType == NULL ) {
1084 rc = LDAP_NO_MEMORY;
1087 attrType->bv_val = LDAP_STRNDUP( startPos, len );
1088 if ( attrType->bv_val == NULL ) {
1089 rc = LDAP_NO_MEMORY;
1092 attrType->bv_len = len;
1098 /* spaces may not be allowed */
1099 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1100 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1105 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1110 /* need equal sign */
1111 if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1116 /* spaces may not be allowed */
1117 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1118 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1123 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1129 * octothorpe means a BER encoded value will follow
1130 * FIXME: I don't think DCE will allow it
1132 if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1134 attrValueEncoding = LDAP_AVA_BINARY;
1135 state = B4BINARYVALUE;
1139 /* STRING value expected */
1142 * if we're pedantic, an attribute type in OID form
1143 * SHOULD imply a BER encoded attribute value; we
1144 * should at least issue a warning
1146 if ( ( flags & LDAP_DN_PEDANTIC )
1147 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1148 /* OID attrType SHOULD use binary encoding */
1152 attrValueEncoding = LDAP_AVA_STRING;
1155 * LDAPv2 allows the attribute value to be quoted;
1156 * also, IA5 values are expected, in principle
1158 if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1159 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1161 state = B4IA5VALUEQUOTED;
1165 if ( LDAP_DN_LDAPV2( flags ) ) {
1172 * here STRING means RFC 2253 string
1173 * FIXME: what about DCE strings?
1175 state = B4STRINGVALUE;
1179 if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
1187 switch ( LDAP_DN_FORMAT( flags ) ) {
1188 case LDAP_DN_FORMAT_LDAP:
1189 case LDAP_DN_FORMAT_LDAPV3:
1190 if ( str2strval( p, &attrValue, &p, flags,
1191 &attrValueEncoding ) ) {
1196 case LDAP_DN_FORMAT_DCE:
1197 if ( DCE2strval( p, &attrValue, &p, flags ) ) {
1210 if ( IA52strval( p, &attrValue, &p, flags ) ) {
1217 case B4IA5VALUEQUOTED:
1219 /* lead quote already stripped */
1220 if ( quotedIA52strval( p, &attrValue,
1231 if ( !( flags & LDAP_DN_SKIP ) ) {
1236 * we accept empty values
1238 ava = ldapava_new( attrType, attrValue,
1239 attrValueEncoding );
1240 if ( ava == NULL ) {
1241 rc = LDAP_NO_MEMORY;
1245 rdn = ldapava_append_to_rdn( newRDN, ava );
1246 if ( rdn == NULL ) {
1247 rc = LDAP_NO_MEMORY;
1254 * if we got an AVA separator ('+', or ',' for DCE )
1255 * we expect a new AVA for this RDN; otherwise
1256 * we add the RDN to the DN
1258 switch ( LDAP_DN_FORMAT( flags ) ) {
1259 case LDAP_DN_FORMAT_LDAP:
1260 case LDAP_DN_FORMAT_LDAPV3:
1261 case LDAP_DN_FORMAT_LDAPV2:
1262 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1267 case LDAP_DN_FORMAT_DCE:
1268 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1276 * the RDN is over, phew
1283 /* they should have been used in an AVA */
1299 /* They are set to NULL after they're used in an AVA */
1301 ber_bvfree( attrType );
1305 ber_bvfree( attrValue );
1309 ldap_rdnfree( newRDN );
1315 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n",
1325 * reads in a UTF-8 string value, unescaping stuff:
1326 * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1327 * '\' + HEXPAIR(p) -> unhex(p)
1330 str2strval( const char *str, struct berval **val, const char **next, unsigned flags, unsigned *retFlags )
1332 const char *p, *startPos, *endPos = NULL;
1333 ber_len_t len, escapes, unescapes;
1342 for ( startPos = p = str, escapes = 0, unescapes = 0; p[ 0 ]; p++ ) {
1343 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1345 if ( p[ 0 ] == '\0' ) {
1348 if ( ( p == startPos + 1 && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1349 || ( LDAP_DN_VALUE_END( p[ 1 ] ) && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
1350 || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1355 if ( LDAP_DN_HEXPAIR( p ) ) {
1358 hexstr2bin( p, &c );
1361 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1364 * we assume the string is UTF-8
1366 *retFlags = LDAP_AVA_NONPRINTABLE;
1373 if ( LDAP_DN_PEDANTIC & flags ) {
1377 * FIXME: we allow escaping
1378 * of chars that don't need
1379 * to and do not belong to
1380 * HEXDIGITS (we also allow
1381 * single hexdigit; maybe we
1386 } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) )
1387 || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1390 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1392 * FIXME: maybe we can add
1393 * escapes if not pedantic?
1400 * we do allow unescaped spaces at the end
1401 * of the value only in non-pedantic mode
1403 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1404 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1405 if ( flags & LDAP_DN_PEDANTIC ) {
1409 /* strip trailing (unescaped) spaces */
1410 for ( endPos = p - 1;
1411 endPos > startPos + 1 &&
1412 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1413 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1420 if ( flags & LDAP_DN_SKIP ) {
1425 * FIXME: test memory?
1427 len = ( endPos ? endPos : p ) - startPos - escapes - unescapes;
1428 *val = LDAP_MALLOC( sizeof( struct berval ) );
1429 ( *val )->bv_len = len;
1431 if ( escapes == 0 && unescapes == 0 ) {
1432 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1437 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1438 for ( s = 0, d = 0; d < len; ) {
1439 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1441 if ( ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( startPos[ s ] ) )
1442 || ( s == len - 1 && LDAP_DN_NEEDESCAPE_TRAIL( startPos[ s ] ) )
1443 || LDAP_DN_NEEDESCAPE( startPos[ s ] ) ) {
1444 ( *val )->bv_val[ d++ ] =
1447 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1450 hexstr2bin( &startPos[ s ], &c );
1451 ( *val )->bv_val[ d++ ] = c;
1456 * we allow escaping of chars
1457 * that do not need to
1459 ( *val )->bv_val[ d++ ] =
1464 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1468 ( *val )->bv_val[ d ] = '\0';
1469 assert( strlen( ( *val )->bv_val ) == len );
1476 DCE2strval( const char *str, struct berval **val, const char **next, unsigned flags )
1478 const char *p, *startPos, *endPos = NULL;
1479 ber_len_t len, escapes;
1488 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1489 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1491 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1498 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1503 * FIXME: can we accept anything else? I guess we need
1504 * to stop if a value is not legal
1509 * (unescaped) trailing spaces are trimmed must be silently ignored;
1512 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1513 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1514 if ( flags & LDAP_DN_PEDANTIC ) {
1518 /* strip trailing (unescaped) spaces */
1519 for ( endPos = p - 1;
1520 endPos > startPos + 1 &&
1521 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1522 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1529 if ( flags & LDAP_DN_SKIP ) {
1533 len = ( endPos ? endPos : p ) - startPos - escapes;
1534 *val = LDAP_MALLOC( sizeof( struct berval ) );
1535 ( *val )->bv_len = len;
1536 if ( escapes == 0 ){
1537 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1542 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1543 for ( s = 0, d = 0; d < len; ) {
1545 * This point is reached only if escapes
1546 * are properly used, so all we need to
1549 if ( LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1553 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1555 ( *val )->bv_val[ d ] = '\0';
1556 assert( strlen( ( *val )->bv_val ) == len );
1563 IA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1565 const char *p, *startPos, *endPos = NULL;
1566 ber_len_t len, escapes;
1579 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1580 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1582 if ( p[ 0 ] == '\0' ) {
1586 if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1587 && ( LDAP_DN_PEDANTIC & flags ) ) {
1592 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1597 * FIXME: can we accept anything else? I guess we need
1598 * to stop if a value is not legal
1602 /* strip trailing (unescaped) spaces */
1604 endPos > startPos + 1 &&
1605 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1606 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1612 if ( flags & LDAP_DN_SKIP ) {
1616 *val = LDAP_MALLOC( sizeof( struct berval ) );
1617 len = ( endPos ? endPos : p ) - startPos - escapes;
1618 ( *val )->bv_len = len;
1619 if ( escapes == 0 ) {
1620 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1625 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1626 for ( s = 0, d = 0; d < len; ) {
1627 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1630 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1632 ( *val )->bv_val[ d ] = '\0';
1633 assert( strlen( ( *val )->bv_val ) == len );
1640 quotedIA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1642 const char *p, *startPos, *endPos = NULL;
1644 unsigned escapes = 0;
1653 /* initial quote already eaten */
1654 for ( startPos = p = str; p[ 0 ]; p++ ) {
1656 * According to RFC 1779, the quoted value can
1657 * contain escaped as well as unescaped special values;
1658 * as a consequence we tolerate escaped values
1659 * (e.g. '"\,"' -> '\,') and escape unescaped specials
1660 * (e.g. '","' -> '\,').
1662 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1663 if ( p[ 1 ] == '\0' ) {
1668 if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1669 && ( LDAP_DN_PEDANTIC & flags ) ) {
1671 * do we allow to escape normal chars?
1672 * LDAPv2 does not allow any mechanism
1673 * for escaping chars with '\' and hex
1680 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1682 /* eat closing quotes */
1688 * FIXME: can we accept anything else? I guess we need
1689 * to stop if a value is not legal
1693 if ( endPos == NULL ) {
1697 /* Strip trailing (unescaped) spaces */
1698 for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1703 if ( flags & LDAP_DN_SKIP ) {
1707 len = endPos - startPos - escapes;
1709 *val = LDAP_MALLOC( sizeof( struct berval ) );
1710 ( *val )->bv_len = len;
1711 if ( escapes == 0 ) {
1712 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1717 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1718 ( *val )->bv_len = len;
1720 for ( s = d = 0; d < len; ) {
1721 if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1724 ( *val )->bv_val[ d++ ] = str[ s++ ];
1726 ( *val )->bv_val[ d ] = '\0';
1727 assert( strlen( ( *val )->bv_val ) == len );
1734 hexstr2bin( const char *str, char *c )
1744 if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1748 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c1 ) ) {
1751 assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) );
1758 if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1762 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c2 ) ) {
1763 *c += c2 - 'A' + 10;
1765 assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) );
1766 *c += c2 - 'a' + 10;
1774 hexstr2binval( const char *str, struct berval **val, const char **next, unsigned flags )
1776 const char *p, *startPos, *endPos = NULL;
1787 for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1788 switch ( LDAP_DN_FORMAT( flags ) ) {
1789 case LDAP_DN_FORMAT_LDAPV3:
1790 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1795 case LDAP_DN_FORMAT_LDAP:
1796 case LDAP_DN_FORMAT_LDAPV2:
1797 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1802 case LDAP_DN_FORMAT_DCE:
1803 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1809 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1810 if ( flags & LDAP_DN_PEDANTIC ) {
1815 for ( ; p[ 0 ]; p++ ) {
1816 switch ( LDAP_DN_FORMAT( flags ) ) {
1817 case LDAP_DN_FORMAT_LDAPV3:
1818 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1823 case LDAP_DN_FORMAT_LDAP:
1824 case LDAP_DN_FORMAT_LDAPV2:
1825 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1830 case LDAP_DN_FORMAT_DCE:
1831 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1840 if ( !LDAP_DN_HEXPAIR( p ) ) {
1848 if ( flags & LDAP_DN_SKIP ) {
1852 len = ( ( endPos ? endPos : p ) - startPos ) / 2;
1854 assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
1856 *val = LDAP_MALLOC( sizeof( struct berval ) );
1857 if ( *val == NULL ) {
1858 return( LDAP_NO_MEMORY );
1861 ( *val )->bv_len = len;
1862 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1863 if ( ( *val )->bv_val == NULL ) {
1865 return( LDAP_NO_MEMORY );
1868 for ( s = 0, d = 0; d < len; s += 2, d++ ) {
1871 hexstr2bin( &startPos[ s ], &c );
1873 ( *val )->bv_val[ d ] = c;
1876 ( *val )->bv_val[ d ] = '\0';
1882 * convert a byte in a hexadecimal pair
1885 byte2hexpair( const char *val, char *pair )
1887 static const char hexdig[] = "0123456789ABCDEF";
1893 * we assume the string has enough room for the hex encoding
1897 pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
1898 pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
1904 * convert a binary value in hexadecimal pairs
1907 binval2hexstr( struct berval *val, char *str )
1914 if ( val->bv_len == 0 ) {
1919 * we assume the string has enough room for the hex encoding
1923 for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
1924 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1931 * Length of the string representation, accounting for escaped hex
1935 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
1937 ber_len_t l, cl = 1;
1939 int escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3;
1940 #ifdef PRETTY_ESCAPE
1941 int escaped_ascii_len = LDAP_DN_IS_PRETTY( flags ) ? 2 : 3;
1942 #endif /* PRETTY_ESCAPE */
1948 if ( val->bv_len == 0 ) {
1952 for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
1953 cl = LDAP_UTF8_CHARLEN( p );
1955 /* illegal utf-8 char! */
1958 } else if ( cl > 1 ) {
1961 for ( cnt = 1; cnt < cl; cnt++ ) {
1962 if ( ( p[ cnt ] & 0x80 ) == 0x00 ) {
1966 l += escaped_byte_len * cl;
1968 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
1969 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1970 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
1971 #ifdef PRETTY_ESCAPE
1972 if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) {
1975 * there might be some chars we want
1976 * to escape in form of a couple
1977 * of hexdigits for optimization purposes
1982 l += escaped_ascii_len;
1984 #else /* ! PRETTY_ESCAPE */
1986 #endif /* ! PRETTY_ESCAPE */
1999 * convert to string representation, escaping with hex the UTF-8 stuff;
2000 * assume the destination has enough room for escaping
2003 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2005 ber_len_t s, d, end;
2011 if ( val->bv_len == 0 ) {
2017 * we assume the string has enough room for the hex encoding
2020 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2021 ber_len_t cl = LDAP_UTF8_CHARLEN( &val->bv_val[ s ] );
2024 * there might be some chars we want to escape in form
2025 * of a couple of hexdigits for optimization purposes
2027 if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) )
2028 #ifdef PRETTY_ESCAPE
2029 || LDAP_DN_WILLESCAPE_HEX( flags, val->bv_val[ s ] )
2030 #else /* ! PRETTY_ESCAPE */
2031 || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2032 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2033 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
2035 #endif /* ! PRETTY_ESCAPE */
2039 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2044 } else if ( cl > 1 ) {
2046 str[ d++ ] = val->bv_val[ s++ ];
2050 #ifdef PRETTY_ESCAPE
2051 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2052 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2053 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2055 if ( !LDAP_DN_IS_PRETTY( flags ) ) {
2056 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
2062 #endif /* PRETTY_ESCAPE */
2063 str[ d++ ] = val->bv_val[ s++ ];
2073 * Length of the IA5 string representation (no UTF-8 allowed)
2076 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
2085 if ( val->bv_len == 0 ) {
2089 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2091 * Turn value into a binary encoded BER
2096 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2097 if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2098 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2099 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2114 * convert to string representation (np UTF-8)
2115 * assume the destination has enough room for escaping
2118 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2120 ber_len_t s, d, end;
2126 if ( val->bv_len == 0 ) {
2131 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2133 * Turn value into a binary encoded BER
2140 * we assume the string has enough room for the hex encoding
2144 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2145 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2146 || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2147 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2150 str[ d++ ] = val->bv_val[ s++ ];
2160 * Length of the (supposedly) DCE string representation,
2161 * accounting for escaped hex of UTF-8 chars
2164 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2173 if ( val->bv_len == 0 ) {
2177 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2179 * FIXME: Turn the value into a binary encoded BER?
2184 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2185 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2200 * convert to (supposedly) DCE string representation,
2201 * escaping with hex the UTF-8 stuff;
2202 * assume the destination has enough room for escaping
2205 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2213 if ( val->bv_len == 0 ) {
2218 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2220 * FIXME: Turn the value into a binary encoded BER?
2228 * we assume the string has enough room for the hex encoding
2232 for ( s = 0, d = 0; s < val->bv_len; ) {
2233 if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2236 str[ d++ ] = val->bv_val[ s++ ];
2246 * Length of the (supposedly) AD canonical string representation,
2247 * accounting for escaped hex of UTF-8 chars
2250 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2259 if ( val->bv_len == 0 ) {
2263 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2265 * FIXME: Turn the value into a binary encoded BER?
2270 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2271 if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2286 * convert to (supposedly) AD string representation,
2287 * escaping with hex the UTF-8 stuff;
2288 * assume the destination has enough room for escaping
2291 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2299 if ( val->bv_len == 0 ) {
2304 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2306 * FIXME: Turn the value into a binary encoded BER?
2314 * we assume the string has enough room for the hex encoding
2318 for ( s = 0, d = 0; s < val->bv_len; ) {
2319 if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2322 str[ d++ ] = val->bv_val[ s++ ];
2332 * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2333 * the first part of the AD representation of the DN is written in DNS
2334 * form, i.e. dot separated domain name components (as suggested
2335 * by Luke Howard, http://www.padl.com/~lukeh)
2338 dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN )
2341 int domain = 0, first = 1;
2342 ber_len_t l = 1; /* we move the null also */
2345 /* we are guaranteed there's enough memory in str */
2351 assert( *iRDN >= 0 );
2353 str = bv->bv_val + pos;
2355 for ( i = *iRDN; i >= 0; i-- ) {
2359 assert( dn[ i ][ 0 ] );
2362 assert( rdn[ 0 ][ 0 ] );
2363 ava = rdn[ 0 ][ 0 ];
2365 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2373 AC_MEMCPY( str, ava->la_value->bv_val,
2374 ava->la_value->bv_len + 1);
2375 l += ava->la_value->bv_len;
2378 AC_MEMCPY( str + ava->la_value->bv_len + 1, bv->bv_val, l);
2379 AC_MEMCPY( str, ava->la_value->bv_val,
2380 ava->la_value->bv_len );
2381 str[ ava->la_value->bv_len ] = '.';
2382 l += ava->la_value->bv_len + 1;
2387 bv->bv_len = pos + l - 1;
2393 rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
2394 int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2401 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2402 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2404 /* len(type) + '=' + '+' | ',' */
2405 l += ava->la_attr->bv_len + 2;
2407 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2408 /* octothorpe + twice the length */
2409 l += 1 + 2 * ava->la_value->bv_len;
2413 unsigned f = flags | ava->la_flags;
2415 if ( ( *s2l )( ava->la_value, f, &vl ) ) {
2428 rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
2429 int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2434 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2435 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2437 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2438 ava->la_attr->bv_len );
2439 l += ava->la_attr->bv_len;
2443 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2445 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2448 l += 2 * ava->la_value->bv_len;
2452 unsigned f = flags | ava->la_flags;
2454 if ( ( *s2s )( ava->la_value, &str[ l ], f, &vl ) ) {
2459 str[ l++ ] = ( rdn[ iAVA + 1 ] ? '+' : ',' );
2468 rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2475 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2476 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2478 /* len(type) + '=' + ',' | '/' */
2479 l += ava->la_attr->bv_len + 2;
2481 switch ( ava->la_flags ) {
2482 case LDAP_AVA_BINARY:
2483 /* octothorpe + twice the length */
2484 l += 1 + 2 * ava->la_value->bv_len;
2487 case LDAP_AVA_STRING: {
2489 unsigned f = flags | ava->la_flags;
2491 if ( strval2DCEstrlen( ava->la_value, f, &vl ) ) {
2509 rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2514 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2515 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2520 str[ l++ ] = ( iAVA ? ',' : '/' );
2523 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val,
2524 ava->la_attr->bv_len );
2525 l += ava->la_attr->bv_len;
2529 switch ( ava->la_flags ) {
2530 case LDAP_AVA_BINARY:
2532 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2535 l += 2 * ava->la_value->bv_len;
2538 case LDAP_AVA_STRING: {
2540 unsigned f = flags | ava->la_flags;
2542 if ( strval2DCEstr( ava->la_value, &str[ l ], f, &vl ) ) {
2560 rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2570 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2571 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2574 l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
2576 /* FIXME: are binary values allowed in UFN? */
2577 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2578 /* octothorpe + twice the value */
2579 l += 1 + 2 * ava->la_value->bv_len;
2583 unsigned f = flags | ava->la_flags;
2585 if ( strval2strlen( ava->la_value, f, &vl ) ) {
2598 rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
2603 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2604 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2606 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2608 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2611 l += 2 * ava->la_value->bv_len;
2615 unsigned f = flags | ava->la_flags;
2617 if ( strval2str( ava->la_value, &str[ l ], f, &vl ) ) {
2623 if ( rdn[ iAVA + 1 ]) {
2624 AC_MEMCPY( &str[ l ], " + ", 3 );
2628 AC_MEMCPY( &str[ l ], ", ", 2 );
2639 rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2649 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2650 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2655 /* FIXME: are binary values allowed in UFN? */
2656 switch ( ava->la_flags ) {
2657 case LDAP_AVA_BINARY:
2658 /* octothorpe + twice the value */
2659 l += 1 + 2 * ava->la_value->bv_len;
2662 case LDAP_AVA_STRING: {
2664 unsigned f = flags | ava->la_flags;
2666 if ( strval2ADstrlen( ava->la_value, f, &vl ) ) {
2684 rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2689 for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2690 LDAPAVA *ava = rdn[ iAVA ][ 0 ];
2695 str[ l++ ] = ( iAVA ? ',' : '/' );
2698 switch ( ava->la_flags ) {
2699 case LDAP_AVA_BINARY:
2701 if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2704 l += 2 * ava->la_value->bv_len;
2707 case LDAP_AVA_STRING: {
2709 unsigned f = flags | ava->la_flags;
2711 if ( strval2ADstr( ava->la_value, &str[ l ], f, &vl ) ) {
2731 * Returns in str a string representation of rdn based on flags.
2732 * There is some duplication of code between this and ldap_dn2str;
2733 * this is wanted to reduce the allocation of temporary buffers.
2736 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2743 rc = ldap_rdn2bv( rdn, &bv, flags );
2749 ldap_rdn2bv( LDAPRDN *rdn, struct berval *bv, unsigned flags )
2759 if ( rdn == NULL ) {
2760 bv->bv_val = LDAP_STRDUP( "" );
2761 return( LDAP_SUCCESS );
2765 * This routine wastes "back" bytes at the end of the string
2768 switch ( LDAP_DN_FORMAT( flags ) ) {
2769 case LDAP_DN_FORMAT_LDAPV3:
2770 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2771 return( LDAP_OTHER );
2775 case LDAP_DN_FORMAT_LDAPV2:
2776 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2777 return( LDAP_OTHER );
2781 case LDAP_DN_FORMAT_UFN:
2782 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2783 return( LDAP_OTHER );
2787 case LDAP_DN_FORMAT_DCE:
2788 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2789 return( LDAP_OTHER );
2793 case LDAP_DN_FORMAT_AD_CANONICAL:
2794 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2795 return( LDAP_OTHER );
2800 return( LDAP_INVALID_DN_SYNTAX );
2803 bv->bv_val = LDAP_MALLOC( l + 1 );
2805 switch ( LDAP_DN_FORMAT( flags ) ) {
2806 case LDAP_DN_FORMAT_LDAPV3:
2807 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2str );
2811 case LDAP_DN_FORMAT_LDAPV2:
2812 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2IA5str );
2816 case LDAP_DN_FORMAT_UFN:
2817 rc = rdn2UFNstr( rdn, bv->bv_val, flags, &l );
2821 case LDAP_DN_FORMAT_DCE:
2822 rc = rdn2DCEstr( rdn, bv->bv_val, flags, &l, 1 );
2826 case LDAP_DN_FORMAT_AD_CANONICAL:
2827 rc = rdn2ADstr( rdn, bv->bv_val, flags, &l, 1 );
2832 /* need at least one of the previous */
2833 return( LDAP_OTHER );
2837 ldap_memfree( bv->bv_val );
2838 return( LDAP_OTHER );
2841 bv->bv_len = l - back;
2842 bv->bv_val[ bv->bv_len ] = '\0';
2844 return( LDAP_SUCCESS );
2848 * Very bulk implementation; many optimizations can be performed
2849 * - a NULL dn results in an empty string ""
2852 * a) what do we do if a UTF-8 string must be converted in LDAPv2?
2853 * we must encode it in binary form ('#' + HEXPAIRs)
2854 * b) does DCE/AD support UTF-8?
2855 * no clue; don't think so.
2856 * c) what do we do when binary values must be converted in UTF/DCE/AD?
2857 * use binary encoded BER
2859 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
2866 rc = ldap_dn2bv( dn, &bv, flags );
2871 int ldap_dn2bv( LDAPDN *dn, struct berval *bv, unsigned flags )
2874 int rc = LDAP_OTHER;
2877 /* stringifying helpers for LDAPv3/LDAPv2 */
2878 int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2879 int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2886 Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2bv(%u)\n%s%s", flags, "", "" );
2889 * a null dn means an empty dn string
2890 * FIXME: better raise an error?
2893 bv->bv_val = LDAP_STRDUP( "" );
2894 return( LDAP_SUCCESS );
2897 switch ( LDAP_DN_FORMAT( flags ) ) {
2898 case LDAP_DN_FORMAT_LDAPV3:
2899 sv2l = strval2strlen;
2903 case LDAP_DN_FORMAT_LDAPV2:
2904 sv2l = strval2IA5strlen;
2905 sv2s = strval2IA5str;
2908 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2910 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2912 if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
2913 goto return_results;
2919 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2920 rc = LDAP_NO_MEMORY;
2924 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
2926 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2928 if ( rdn2str( rdn, &bv->bv_val[ l ], flags,
2930 LDAP_FREE( bv->bv_val );
2932 goto return_results;
2940 * trim the last ',' (the allocated memory
2941 * is one byte longer than required)
2943 bv->bv_len = len - 1;
2944 bv->bv_val[ bv->bv_len ] = '\0';
2949 case LDAP_DN_FORMAT_UFN: {
2952 * FIXME: quoting from RFC 1781:
2954 To take a distinguished name, and generate a name of this format with
2955 attribute types omitted, the following steps are followed.
2957 1. If the first attribute is of type CommonName, the type may be
2960 2. If the last attribute is of type Country, the type may be
2963 3. If the last attribute is of type Country, the last
2964 Organisation attribute may have the type omitted.
2966 4. All attributes of type OrganisationalUnit may have the type
2967 omitted, unless they are after an Organisation attribute or
2968 the first attribute is of type OrganisationalUnit.
2970 * this should be the pedantic implementation.
2972 * Here the standard implementation reflects
2973 * the one historically provided by OpenLDAP
2974 * (and UMIch, I presume), with the variant
2975 * of spaces and plusses (' + ') separating
2978 * A non-standard but nice implementation could
2979 * be to turn the final "dc" attributes into a
2980 * dot-separated domain.
2982 * Other improvements could involve the use of
2983 * friendly country names and so.
2986 int leftmost_dc = -1;
2988 #endif /* DC_IN_UFN */
2990 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2992 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
2994 if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
2995 goto return_results;
3000 if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
3001 if ( leftmost_dc == -1 ) {
3007 #endif /* DC_IN_UFN */
3010 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3011 rc = LDAP_NO_MEMORY;
3016 if ( leftmost_dc == -1 ) {
3017 #endif /* DC_IN_UFN */
3018 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
3020 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3022 if ( rdn2UFNstr( rdn, &bv->bv_val[ l ],
3024 LDAP_FREE( bv->bv_val );
3026 goto return_results;
3032 * trim the last ', ' (the allocated memory
3033 * is two bytes longer than required)
3035 bv->bv_len = len - 2;
3036 bv->bv_val[ bv->bv_len ] = '\0';
3039 last_iRDN = iRDN - 1;
3041 for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
3043 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3045 if ( rdn2UFNstr( rdn, &bv->bv_val[ l ],
3047 LDAP_FREE( bv->bv_val );
3049 goto return_results;
3054 if ( !dn2domain( dn, bv, l, &last_iRDN ) ) {
3055 LDAP_FREE( bv->bv_val );
3057 goto return_results;
3060 /* the string is correctly terminated by dn2domain */
3062 #endif /* DC_IN_UFN */
3068 case LDAP_DN_FORMAT_DCE:
3070 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
3072 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3074 if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
3075 goto return_results;
3081 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3082 rc = LDAP_NO_MEMORY;
3086 for ( l = 0; iRDN--; ) {
3088 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3090 if ( rdn2DCEstr( rdn, &bv->bv_val[ l ], flags,
3092 LDAP_FREE( bv->bv_val );
3094 goto return_results;
3102 bv->bv_val[ bv->bv_len ] = '\0';
3107 case LDAP_DN_FORMAT_AD_CANONICAL: {
3110 * Sort of UFN for DCE DNs: a slash ('/') separated
3111 * global->local DN with no types; strictly speaking,
3112 * the naming context should be a domain, which is
3113 * written in DNS-style, e.g. dot-deparated.
3117 * "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3121 * "microsoft.com/People/Bill,Gates"
3123 for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
3125 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3127 if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
3128 goto return_results;
3134 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3135 rc = LDAP_NO_MEMORY;
3140 if ( iRDN && dn2domain( dn, bv, 0, &iRDN ) ) {
3141 for ( l = bv->bv_len; iRDN >= 0 ; iRDN-- ) {
3143 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3145 if ( rdn2ADstr( rdn, &bv->bv_val[ l ],
3146 flags, &rdnl, 0 ) ) {
3147 LDAP_FREE( bv->bv_val );
3149 goto return_results;
3158 * Strictly speaking, AD canonical requires
3159 * a DN to be in the form "..., dc=smtg",
3160 * i.e. terminated by a domain component
3162 if ( flags & LDAP_DN_PEDANTIC ) {
3163 LDAP_FREE( bv->bv_val );
3165 rc = LDAP_INVALID_DN_SYNTAX;
3169 for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3171 LDAPRDN *rdn = dn[ iRDN ][ 0 ];
3173 if ( rdn2ADstr( rdn, &bv->bv_val[ l ],
3174 flags, &rdnl, first ) ) {
3175 LDAP_FREE( bv->bv_val );
3177 goto return_results;
3187 bv->bv_val[ bv->bv_len ] = '\0';
3194 return( LDAP_INVALID_DN_SYNTAX );
3198 Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2bv(%s,%u)=%d\n", bv->bv_val, flags, rc );