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 /* from libraries/libldap/schema.c */
30 extern char * parse_numericoid(const char **sp, int *code, const int flags);
32 /* parsing/printing routines */
33 static int str2strval( const char *str, struct berval *val,
34 const char **next, unsigned flags, unsigned *retFlags );
35 static int DCE2strval( const char *str, struct berval *val,
36 const char **next, unsigned flags );
37 static int IA52strval( const char *str, struct berval *val,
38 const char **next, unsigned flags );
39 static int quotedIA52strval( const char *str, struct berval *val,
40 const char **next, unsigned flags );
41 static int hexstr2binval( const char *str, struct berval *val,
42 const char **next, unsigned flags );
43 static int hexstr2bin( const char *str, char *c );
44 static int byte2hexpair( const char *val, char *pair );
45 static int binval2hexstr( struct berval *val, char *str );
46 static int strval2strlen( struct berval *val, unsigned flags,
48 static int strval2str( struct berval *val, char *str, unsigned flags,
50 static int strval2IA5strlen( struct berval *val, unsigned flags,
52 static int strval2IA5str( struct berval *val, char *str, unsigned flags,
54 static int strval2DCEstrlen( struct berval *val, unsigned flags,
56 static int strval2DCEstr( struct berval *val, char *str, unsigned flags,
58 static int strval2ADstrlen( struct berval *val, unsigned flags,
60 static int strval2ADstr( struct berval *val, char *str, unsigned flags,
62 static int dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN );
65 static LDAPAVA * ldapava_new(
66 const struct berval *attr, const struct berval *val, unsigned flags );
68 /* Higher level helpers */
69 static int rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
70 int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
71 static int rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
72 int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
73 static int rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
74 static int rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len );
75 static int rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
76 static int rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flag, ber_len_t *len, int first );
77 static int rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
78 static int rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first );
81 * RFC 1823 ldap_get_dn
84 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
89 Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
91 if ( entry == NULL ) {
92 ld->ld_errno = LDAP_PARAM_ERROR;
96 tmp = *entry->lm_ber; /* struct copy */
97 if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
98 ld->ld_errno = LDAP_DECODING_ERROR;
106 * RFC 1823 ldap_dn2ufn
109 ldap_dn2ufn( LDAP_CONST char *dn )
113 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
115 ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP,
116 &out, LDAP_DN_FORMAT_UFN );
122 * RFC 1823 ldap_explode_dn
125 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
128 char **values = NULL;
130 unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
132 Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
134 if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP )
139 if( tmpDN == NULL ) {
140 values = LDAP_MALLOC( sizeof( char * ) );
141 if( values == NULL ) return NULL;
147 for ( iRDN = 0; tmpDN[ 0 ][ iRDN ]; iRDN++ );
149 values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iRDN ) );
150 if ( values == NULL ) {
151 ldap_dnfree( tmpDN );
155 for ( iRDN = 0; tmpDN[ 0 ][ iRDN ]; iRDN++ ) {
156 ldap_rdn2str( tmpDN[ 0 ][ iRDN ], &values[ iRDN ], flag );
158 ldap_dnfree( tmpDN );
159 values[ iRDN ] = NULL;
165 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
168 char **values = NULL;
172 Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
175 * we only parse the first rdn
176 * FIXME: we prefer efficiency over checking if the _ENTIRE_
179 if ( ldap_str2rdn( rdn, &tmpRDN, &p, LDAP_DN_FORMAT_LDAP )
184 for ( iAVA = 0; tmpRDN[ 0 ][ iAVA ]; iAVA++ ) ;
185 values = LDAP_MALLOC( sizeof( char * ) * ( 1 + iAVA ) );
186 if ( values == NULL ) {
187 ldap_rdnfree( tmpRDN );
191 for ( iAVA = 0; tmpRDN[ 0 ][ iAVA ]; iAVA++ ) {
192 ber_len_t l = 0, vl, al = 0;
194 LDAPAVA *ava = tmpRDN[ 0 ][ iAVA ];
196 if ( ava->la_flags == LDAP_AVA_BINARY ) {
197 vl = 1 + 2 * ava->la_value.bv_len;
200 if ( strval2strlen( &ava->la_value,
201 ava->la_flags, &vl ) ) {
207 al = ava->la_attr.bv_len;
208 l = vl + ava->la_attr.bv_len + 1;
210 str = LDAP_MALLOC( l + 1 );
211 AC_MEMCPY( str, ava->la_attr.bv_val,
212 ava->la_attr.bv_len );
217 str = LDAP_MALLOC( l + 1 );
220 if ( ava->la_flags == LDAP_AVA_BINARY ) {
222 if ( binval2hexstr( &ava->la_value, &str[ al ] ) ) {
227 if ( strval2str( &ava->la_value, &str[ al ],
228 ava->la_flags, &vl ) ) {
234 values[ iAVA ] = str;
236 values[ iAVA ] = NULL;
238 ldap_rdnfree( tmpRDN );
243 LBER_VFREE( values );
244 ldap_rdnfree( tmpRDN );
249 ldap_dn2dcedn( LDAP_CONST char *dn )
253 Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
255 ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP,
256 &out, LDAP_DN_FORMAT_DCE );
262 ldap_dcedn2dn( LDAP_CONST char *dce )
266 Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
268 ( void )ldap_dn_normalize( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
274 ldap_dn2ad_canonical( LDAP_CONST char *dn )
278 Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
280 ( void )ldap_dn_normalize( dn, LDAP_DN_FORMAT_LDAP,
281 &out, LDAP_DN_FORMAT_AD_CANONICAL );
287 * function that changes the string representation of dnin
288 * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
291 * LDAP_DN_FORMAT_LDAP (rfc 2253 and ldapbis liberal,
292 * plus some rfc 1779)
293 * LDAP_DN_FORMAT_LDAPV3 (rfc 2253 and ldapbis)
294 * LDAP_DN_FORMAT_LDAPV2 (rfc 1779)
295 * LDAP_DN_FORMAT_DCE (?)
297 * fout can be any of the above except
298 * LDAP_DN_FORMAT_LDAP
300 * LDAP_DN_FORMAT_UFN (rfc 1781, partial and with extensions)
301 * LDAP_DN_FORMAT_AD_CANONICAL (?)
304 ldap_dn_normalize( const char *dnin, unsigned fin, char **dnout, unsigned fout )
307 LDAPDN *tmpDN = NULL;
309 Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );
315 if ( dnin == NULL ) {
316 return( LDAP_SUCCESS );
319 rc = ldap_str2dn( dnin , &tmpDN, fin );
320 if ( rc != LDAP_SUCCESS ) {
324 rc = ldap_dn2str( tmpDN, dnout, fout );
326 ldap_dnfree( tmpDN );
334 /* #define B4ATTRTYPE 0x0001 */
335 #define B4OIDATTRTYPE 0x0002
336 #define B4STRINGATTRTYPE 0x0003
338 #define B4AVAEQUALS 0x0100
339 #define B4AVASEP 0x0200
340 #define B4RDNSEP 0x0300
341 #define GOTAVA 0x0400
343 #define B4ATTRVALUE 0x0010
344 #define B4STRINGVALUE 0x0020
345 #define B4IA5VALUEQUOTED 0x0030
346 #define B4IA5VALUE 0x0040
347 #define B4BINARYVALUE 0x0050
350 * Helpers (mostly from slap.h)
351 * c is assumed to Unicode in an ASCII compatible format (UTF-8)
352 * Macros assume "C" Locale (ASCII)
354 #define LDAP_DN_ASCII_SPACE(c) \
355 ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
356 #define LDAP_DN_ASCII_LOWER(c) ( (c) >= 'a' && (c) <= 'z' )
357 #define LDAP_DN_ASCII_UPPER(c) ( (c) >= 'A' && (c) <= 'Z' )
358 #define LDAP_DN_ASCII_ALPHA(c) \
359 ( LDAP_DN_ASCII_LOWER(c) || LDAP_DN_ASCII_UPPER(c) )
360 #define LDAP_DN_ASCII_DIGIT(c) ( (c) >= '0' && (c) <= '9' )
361 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) ( (c) >= 'a' && (c) <= 'f' )
362 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) ( (c) >= 'A' && (c) <= 'F' )
363 #define LDAP_DN_ASCII_HEXDIGIT(c) \
364 ( LDAP_DN_ASCII_DIGIT(c) \
365 || LDAP_DN_ASCII_LCASE_HEXALPHA(c) \
366 || LDAP_DN_ASCII_UCASE_HEXALPHA(c) )
367 #define LDAP_DN_ASCII_ALNUM(c) \
368 ( LDAP_DN_ASCII_ALPHA(c) || LDAP_DN_ASCII_DIGIT(c) )
369 #define LDAP_DN_ASCII_PRINTABLE(c) ( (c) >= ' ' && (c) <= '~' )
372 #define LDAP_DN_OID_LEADCHAR(c) ( LDAP_DN_ASCII_DIGIT(c) )
373 #define LDAP_DN_DESC_LEADCHAR(c) ( LDAP_DN_ASCII_ALPHA(c) )
374 #define LDAP_DN_DESC_CHAR(c) ( LDAP_DN_ASCII_ALNUM(c) || (c) == '-' )
375 #define LDAP_DN_LANG_SEP(c) ( (c) == ';' )
376 #define LDAP_DN_ATTRDESC_CHAR(c) \
377 ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
379 /* special symbols */
380 #define LDAP_DN_AVA_EQUALS(c) ( (c) == '=' )
381 #define LDAP_DN_AVA_SEP(c) ( (c) == '+' )
382 #define LDAP_DN_RDN_SEP(c) ( (c) == ',' )
383 #define LDAP_DN_RDN_SEP_V2(c) ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
384 #define LDAP_DN_OCTOTHORPE(c) ( (c) == '#' )
385 #define LDAP_DN_QUOTES(c) ( (c) == '\"' )
386 #define LDAP_DN_ESCAPE(c) ( (c) == '\\' )
387 #define LDAP_DN_VALUE_END(c) \
388 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
389 #define LDAP_DN_NE(c) \
390 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
391 || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
392 #define LDAP_DN_NEEDESCAPE(c) \
393 ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
394 #define LDAP_DN_NEEDESCAPE_LEAD(c) \
395 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) )
396 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
397 ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
398 #define LDAP_DN_WILLESCAPE_CHAR(c) \
399 ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) || LDAP_DN_ESCAPE(c) )
400 #define LDAP_DN_IS_PRETTY(f) ( (f) & LDAP_DN_PRETTY )
401 #define LDAP_DN_WILLESCAPE_HEX(f, c) \
402 ( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
405 #define LDAP_DN_VALUE_END_V2(c) \
406 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
408 #define LDAP_DN_V2_SPECIAL(c) \
409 ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
410 || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
411 || LDAP_DN_OCTOTHORPE(c) )
412 #define LDAP_DN_V2_PAIR(c) \
413 ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
416 * DCE (mostly from Luke Howard and IBM implementation for AIX)
418 * From: "Application Development Guide - Directory Services" (FIXME: add link?)
419 * Here escapes and valid chars for GDS are considered; as soon as more
420 * specific info is found, the macros will be updated.
422 * Chars: 'a'-'z', 'A'-'Z', '0'-'9',
423 * '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
425 * Metachars: '/', ',', '=', '\'.
427 * the '\' is used to escape other metachars.
433 * Attribute types must start with alphabetic chars and can contain
434 * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
436 #define LDAP_DN_RDN_SEP_DCE(c) ( (c) == '/' )
437 #define LDAP_DN_AVA_SEP_DCE(c) ( (c) == ',' )
438 #define LDAP_DN_ESCAPE_DCE(c) ( LDAP_DN_ESCAPE(c) )
439 #define LDAP_DN_VALUE_END_DCE(c) \
440 ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
441 #define LDAP_DN_NEEDESCAPE_DCE(c) \
442 ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
445 #define LDAP_DN_RDN_SEP_AD(c) ( (c) == '/' )
446 #define LDAP_DN_ESCAPE_AD(c) ( LDAP_DN_ESCAPE(c) )
447 #define LDAP_DN_AVA_SEP_AD(c) ( (c) == ',' ) /* assume same as DCE */
448 #define LDAP_DN_VALUE_END_AD(c) \
449 ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
450 #define LDAP_DN_NEEDESCAPE_AD(c) \
451 ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
454 #define LDAP_DN_HEXPAIR(s) \
455 ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
456 /* better look at the AttributeDescription? */
458 /* FIXME: no composite rdn or non-"dc" types, right?
459 * (what about "dc" in OID form?) */
460 /* FIXME: we do not allow binary values in domain, right? */
461 /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
462 /* NOTE: don't use strcasecmp() as it is locale specific! */
463 #define LDAP_DC_ATTR "dc"
464 #define LDAP_DC_ATTRU "DC"
465 #define LDAP_DN_IS_RDN_DC( r ) \
466 ( (r) && (r)[0][0] && !(r)[1] \
467 && ((r)[0][0]->la_flags == LDAP_AVA_STRING) \
468 && ((r)[0][0]->la_attr.bv_len == 2) \
469 && (((r)[0][0]->la_attr.bv_val[0] == LDAP_DC_ATTR[0]) \
470 || ((r)[0][0]->la_attr.bv_val[0] == LDAP_DC_ATTRU[0])) \
471 && (((r)[0][0]->la_attr.bv_val[1] == LDAP_DC_ATTR[1]) \
472 || ((r)[0][0]->la_attr.bv_val[1] == LDAP_DC_ATTRU[1])))
474 /* Composite rules */
475 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
476 ( LDAP_DN_LDAPV2(f) \
477 || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
478 #define LDAP_DN_ALLOW_SPACES(f) \
479 ( LDAP_DN_LDAPV2(f) \
480 || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
481 #define LDAP_DN_LDAP(f) \
482 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
483 #define LDAP_DN_LDAPV3(f) \
484 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
485 #define LDAP_DN_LDAPV2(f) \
486 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
487 #define LDAP_DN_DCE(f) \
488 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
489 #define LDAP_DN_UFN(f) \
490 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
491 #define LDAP_DN_ADC(f) \
492 ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
493 #define LDAP_DN_FORMAT(f) ( (f) & LDAP_DN_FORMAT_MASK )
496 * LDAPAVA helpers (will become part of the API for operations
497 * on structural representations of DNs).
500 ldapava_new( const struct berval *attr, const struct berval *val,
508 ava = LDAP_MALLOC( sizeof( LDAPAVA ) );
510 /* should we test it? */
515 ava->la_attr = *attr;
516 ava->la_value = *val;
517 ava->la_flags = flags;
519 ava->la_private = NULL;
525 ldap_avafree( LDAPAVA *ava )
530 /* ava's private must be freed by caller
531 * (at present let's skip this check because la_private
532 * basically holds static data) */
533 assert( ava->la_private == NULL );
536 free( ava->la_attr.bv_val );
537 free( ava->la_value.bv_val );
543 ldap_rdnfree( LDAPRDN *rdn )
551 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
552 ldap_avafree( rdn[ 0 ][ iAVA ] );
559 ldap_dnfree( LDAPDN *dn )
567 for ( iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
568 ldap_rdnfree( dn[ 0 ][ iRDN ] );
575 * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
576 * into a structural representation of the DN, by separating attribute
577 * types and values encoded in the more appropriate form, which is
578 * string or OID for attribute types and binary form of the BER encoded
579 * value or Unicode string. Formats different from LDAPv3 are parsed
580 * according to their own rules and turned into the more appropriate
581 * form according to LDAPv3.
583 * NOTE: I realize the code is getting spaghettish; it is rather
584 * experimental and will hopefully turn into something more simple
585 * and readable as soon as it works as expected.
588 #define TMP_SLOTS 256
591 ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
594 int rc = LDAP_INVALID_DN_SYNTAX;
597 LDAPDN *newDN = NULL;
598 LDAPRDN *newRDN = NULL, *tmpDN[TMP_SLOTS];
603 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );
607 switch ( LDAP_DN_FORMAT( flags ) ) {
608 case LDAP_DN_FORMAT_LDAP:
609 case LDAP_DN_FORMAT_LDAPV3:
610 case LDAP_DN_FORMAT_LDAPV2:
611 case LDAP_DN_FORMAT_DCE:
614 /* unsupported in str2dn */
615 case LDAP_DN_FORMAT_UFN:
616 case LDAP_DN_FORMAT_AD_CANONICAL:
617 return( LDAP_INVALID_DN_SYNTAX );
620 return( LDAP_OTHER );
623 if ( str[ 0 ] == '\0' ) {
624 return( LDAP_SUCCESS );
628 if ( LDAP_DN_DCE( flags ) ) {
631 * (from Luke Howard: thnx) A RDN separator is required
632 * at the beginning of an (absolute) DN.
634 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
639 } else if ( LDAP_DN_LDAP( flags ) ) {
641 * if dn starts with '/' let's make it a DCE dn
643 if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
644 flags |= LDAP_DN_FORMAT_DCE;
649 for ( ; p[ 0 ]; p++ ) {
653 err = ldap_str2rdn( p, &newRDN, &p, flags );
654 if ( err != LDAP_SUCCESS ) {
659 * We expect a rdn separator
662 switch ( LDAP_DN_FORMAT( flags ) ) {
663 case LDAP_DN_FORMAT_LDAPV3:
664 if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
670 case LDAP_DN_FORMAT_LDAP:
671 case LDAP_DN_FORMAT_LDAPV2:
672 if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
678 case LDAP_DN_FORMAT_DCE:
679 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
688 tmpDN[nrdns++] = newRDN;
691 assert (nrdns < TMP_SLOTS);
693 if ( p[ 0 ] == '\0' ) {
695 * the DN is over, phew
697 newDN = (LDAPDN *)LDAP_MALLOC( sizeof(LDAPDN) +
698 sizeof(LDAPRDN *) * (nrdns+1));
699 if ( newDN == NULL ) {
705 newDN[0] = (LDAPRDN **)newDN+1;
707 if ( LDAP_DN_DCE( flags ) ) {
708 /* add in reversed order */
709 for ( i=0; i<nrdns; i++ )
710 newDN[0][i] = tmpDN[nrdns-1-i];
712 for ( i=0; i<nrdns; i++ )
713 newDN[0][i] = tmpDN[i];
715 newDN[0][nrdns] = NULL;
724 ldap_rdnfree( newRDN );
727 for (nrdns-- ;nrdns>=0; nrdns-- )
728 ldap_rdnfree( tmpDN[nrdns] );
732 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
741 * Parses a relative DN according to flags up to a rdn separator
742 * or to the end of str.
743 * Returns the rdn and a pointer to the string continuation, which
744 * corresponds to the rdn separator or to '\0' in case the string is over.
747 ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
752 int rc = LDAP_INVALID_DN_SYNTAX;
753 int attrTypeEncoding = LDAP_AVA_STRING,
754 attrValueEncoding = LDAP_AVA_STRING;
756 struct berval attrType = { 0, NULL };
757 struct berval attrValue = { 0, NULL };
759 LDAPRDN *newRDN = NULL;
760 LDAPAVA *tmpRDN[TMP_SLOTS];
763 assert( rdn || flags & LDAP_DN_SKIP );
766 Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );
773 switch ( LDAP_DN_FORMAT( flags ) ) {
774 case LDAP_DN_FORMAT_LDAP:
775 case LDAP_DN_FORMAT_LDAPV3:
776 case LDAP_DN_FORMAT_LDAPV2:
777 case LDAP_DN_FORMAT_DCE:
780 /* unsupported in str2dn */
781 case LDAP_DN_FORMAT_UFN:
782 case LDAP_DN_FORMAT_AD_CANONICAL:
783 return( LDAP_INVALID_DN_SYNTAX );
786 return( LDAP_OTHER );
789 if ( str[ 0 ] == '\0' ) {
790 return( LDAP_SUCCESS );
794 for ( ; p[ 0 ] || state == GOTAVA; ) {
797 * The parser in principle advances one token a time,
798 * or toggles state if preferable.
803 * an AttributeType can be encoded as:
804 * - its string representation; in detail, implementations
805 * MUST recognize AttributeType string type names listed
806 * in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
807 * MAY recognize other names.
808 * - its numeric OID (a dotted decimal string); in detail
809 * RFC 2253 asserts that ``Implementations MUST allow
810 * an oid in the attribute type to be prefixed by one
811 * of the character strings "oid." or "OID."''. As soon
812 * as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253
813 * I'm not sure whether this is required or not any
814 * longer; to be liberal, we still implement it.
817 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
818 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
825 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
826 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
831 /* whitespace is allowed (and trimmed) */
833 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
838 /* error: we expected an AVA */
844 if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
845 state = B4OIDATTRTYPE;
849 /* else must be alpha */
850 if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
854 /* LDAPv2 "oid." prefix */
855 if ( LDAP_DN_LDAPV2( flags ) ) {
857 * to be overly pedantic, we only accept
860 if ( flags & LDAP_DN_PEDANTIC ) {
861 if ( !strncmp( p, "OID.", 4 )
862 || !strncmp( p, "oid.", 4 ) ) {
864 state = B4OIDATTRTYPE;
868 if ( !strncasecmp( p, "oid.", 4 ) ) {
870 state = B4OIDATTRTYPE;
876 state = B4STRINGATTRTYPE;
879 case B4OIDATTRTYPE: {
880 int err = LDAP_SUCCESS;
883 type = parse_numericoid( &p, &err, 0 );
884 if ( type == NULL ) {
888 if ( flags & LDAP_DN_SKIP ) {
890 * FIXME: hack for skipping a rdn;
891 * need a cleaner solution
896 ber_str2bv( type, 0, 0, &attrType );
899 attrTypeEncoding = LDAP_AVA_BINARY;
905 case B4STRINGATTRTYPE: {
906 const char *startPos, *endPos = NULL;
910 * the starting char has been found to be
911 * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
912 * FIXME: DCE attr types seem to have a more
913 * restrictive syntax (no '-' ...)
915 for ( startPos = p++; p[ 0 ]; p++ ) {
916 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
920 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
923 * RFC 2253 does not explicitly
924 * allow lang extensions to attribute
927 if ( flags & LDAP_DN_PEDANTIC ) {
932 * we trim ';' and following lang
933 * and so from attribute types
936 for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
937 || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
945 len = ( endPos ? endPos : p ) - startPos;
950 attrTypeEncoding = LDAP_AVA_STRING;
953 * here we need to decide whether to use it as is
954 * or turn it in OID form; as a consequence, we
955 * need to decide whether to binary encode the value
960 if ( flags & LDAP_DN_SKIP ) {
964 attrType.bv_val = LDAP_STRNDUP( startPos, len );
965 if ( attrType.bv_val == NULL ) {
969 attrType.bv_len = len;
975 /* spaces may not be allowed */
976 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
977 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
982 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
987 /* need equal sign */
988 if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
993 /* spaces may not be allowed */
994 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
995 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1000 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1006 * octothorpe means a BER encoded value will follow
1007 * FIXME: I don't think DCE will allow it
1009 if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1011 attrValueEncoding = LDAP_AVA_BINARY;
1012 state = B4BINARYVALUE;
1016 /* STRING value expected */
1019 * if we're pedantic, an attribute type in OID form
1020 * SHOULD imply a BER encoded attribute value; we
1021 * should at least issue a warning
1023 if ( ( flags & LDAP_DN_PEDANTIC )
1024 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1025 /* OID attrType SHOULD use binary encoding */
1029 attrValueEncoding = LDAP_AVA_STRING;
1032 * LDAPv2 allows the attribute value to be quoted;
1033 * also, IA5 values are expected, in principle
1035 if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1036 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1038 state = B4IA5VALUEQUOTED;
1042 if ( LDAP_DN_LDAPV2( flags ) ) {
1049 * here STRING means RFC 2253 string
1050 * FIXME: what about DCE strings?
1052 state = B4STRINGVALUE;
1056 if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
1064 switch ( LDAP_DN_FORMAT( flags ) ) {
1065 case LDAP_DN_FORMAT_LDAP:
1066 case LDAP_DN_FORMAT_LDAPV3:
1067 if ( str2strval( p, &attrValue, &p, flags,
1068 &attrValueEncoding ) ) {
1073 case LDAP_DN_FORMAT_DCE:
1074 if ( DCE2strval( p, &attrValue, &p, flags ) ) {
1087 if ( IA52strval( p, &attrValue, &p, flags ) ) {
1094 case B4IA5VALUEQUOTED:
1096 /* lead quote already stripped */
1097 if ( quotedIA52strval( p, &attrValue,
1108 if ( !( flags & LDAP_DN_SKIP ) ) {
1112 * we accept empty values
1114 ava = ldapava_new( &attrType, &attrValue,
1115 attrValueEncoding );
1116 if ( ava == NULL ) {
1117 rc = LDAP_NO_MEMORY;
1120 tmpRDN[navas++] = ava;
1122 assert(navas < TMP_SLOTS);
1126 * if we got an AVA separator ('+', or ',' for DCE )
1127 * we expect a new AVA for this RDN; otherwise
1128 * we add the RDN to the DN
1130 switch ( LDAP_DN_FORMAT( flags ) ) {
1131 case LDAP_DN_FORMAT_LDAP:
1132 case LDAP_DN_FORMAT_LDAPV3:
1133 case LDAP_DN_FORMAT_LDAPV2:
1134 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1139 case LDAP_DN_FORMAT_DCE:
1140 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1148 * the RDN is over, phew
1151 if ( !( flags & LDAP_DN_SKIP ) ) {
1152 newRDN = (LDAPRDN *)LDAP_MALLOC( sizeof(LDAPRDN)
1153 + sizeof(LDAPAVA *) * (navas+1) );
1154 if ( newRDN == NULL ) {
1155 rc = LDAP_NO_MEMORY;
1160 newRDN[0] = (LDAPAVA**) newRDN+1;
1162 for (i=0; i<navas; i++)
1163 newRDN[0][i] = tmpRDN[i];
1164 newRDN[0][i] = NULL;
1172 /* they should have been used in an AVA */
1173 attrType.bv_val = NULL;
1174 attrValue.bv_val = NULL;
1188 /* They are set to NULL after they're used in an AVA */
1189 if ( attrType.bv_val ) {
1190 free( attrType.bv_val );
1193 if ( attrValue.bv_val ) {
1194 free( attrValue.bv_val );
1197 for (navas-- ; navas>=0; navas-- )
1198 ldap_avafree( tmpRDN[navas] );
1202 Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n",
1212 * reads in a UTF-8 string value, unescaping stuff:
1213 * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1214 * '\' + HEXPAIR(p) -> unhex(p)
1217 str2strval( const char *str, struct berval *val, const char **next, unsigned flags, unsigned *retFlags )
1219 const char *p, *startPos, *endPos = NULL;
1220 ber_len_t len, escapes, unescapes;
1228 for ( startPos = p = str, escapes = 0, unescapes = 0; p[ 0 ]; p++ ) {
1229 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1231 if ( p[ 0 ] == '\0' ) {
1234 if ( ( p == startPos + 1 && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1235 || ( LDAP_DN_VALUE_END( p[ 1 ] ) && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
1236 || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1241 if ( LDAP_DN_HEXPAIR( p ) ) {
1244 hexstr2bin( p, &c );
1247 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1250 * we assume the string is UTF-8
1252 *retFlags = LDAP_AVA_NONPRINTABLE;
1259 if ( LDAP_DN_PEDANTIC & flags ) {
1263 * FIXME: we allow escaping
1264 * of chars that don't need
1265 * to and do not belong to
1266 * HEXDIGITS (we also allow
1267 * single hexdigit; maybe we
1272 } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) )
1273 || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1276 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1278 * FIXME: maybe we can add
1279 * escapes if not pedantic?
1286 * we do allow unescaped spaces at the end
1287 * of the value only in non-pedantic mode
1289 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1290 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1291 if ( flags & LDAP_DN_PEDANTIC ) {
1295 /* strip trailing (unescaped) spaces */
1296 for ( endPos = p - 1;
1297 endPos > startPos + 1 &&
1298 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1299 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1306 if ( flags & LDAP_DN_SKIP ) {
1311 * FIXME: test memory?
1313 len = ( endPos ? endPos : p ) - startPos - escapes - unescapes;
1316 if ( escapes == 0 && unescapes == 0 ) {
1317 val->bv_val = LDAP_STRNDUP( startPos, len );
1322 val->bv_val = LDAP_MALLOC( len + 1 );
1323 for ( s = 0, d = 0; d < len; ) {
1324 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1326 if ( ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( startPos[ s ] ) )
1327 || ( s == len - 1 && LDAP_DN_NEEDESCAPE_TRAIL( startPos[ s ] ) )
1328 || LDAP_DN_NEEDESCAPE( startPos[ s ] ) ) {
1329 val->bv_val[ d++ ] =
1332 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1335 hexstr2bin( &startPos[ s ], &c );
1336 val->bv_val[ d++ ] = c;
1341 * we allow escaping of chars
1342 * that do not need to
1344 val->bv_val[ d++ ] =
1349 val->bv_val[ d++ ] = startPos[ s++ ];
1353 val->bv_val[ d ] = '\0';
1354 assert( strlen( val->bv_val ) == len );
1361 DCE2strval( const char *str, struct berval *val, const char **next, unsigned flags )
1363 const char *p, *startPos, *endPos = NULL;
1364 ber_len_t len, escapes;
1372 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1373 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1375 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1382 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1387 * FIXME: can we accept anything else? I guess we need
1388 * to stop if a value is not legal
1393 * (unescaped) trailing spaces are trimmed must be silently ignored;
1396 if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1397 !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1398 if ( flags & LDAP_DN_PEDANTIC ) {
1402 /* strip trailing (unescaped) spaces */
1403 for ( endPos = p - 1;
1404 endPos > startPos + 1 &&
1405 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1406 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1413 if ( flags & LDAP_DN_SKIP ) {
1417 len = ( endPos ? endPos : p ) - startPos - escapes;
1419 if ( escapes == 0 ){
1420 val->bv_val = LDAP_STRNDUP( startPos, len );
1425 val->bv_val = LDAP_MALLOC( len + 1 );
1426 for ( s = 0, d = 0; d < len; ) {
1428 * This point is reached only if escapes
1429 * are properly used, so all we need to
1432 if ( LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1436 val->bv_val[ d++ ] = startPos[ s++ ];
1438 val->bv_val[ d ] = '\0';
1439 assert( strlen( val->bv_val ) == len );
1446 IA52strval( const char *str, struct berval *val, const char **next, unsigned flags )
1448 const char *p, *startPos, *endPos = NULL;
1449 ber_len_t len, escapes;
1461 for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1462 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1464 if ( p[ 0 ] == '\0' ) {
1468 if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1469 && ( LDAP_DN_PEDANTIC & flags ) ) {
1474 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1479 * FIXME: can we accept anything else? I guess we need
1480 * to stop if a value is not legal
1484 /* strip trailing (unescaped) spaces */
1486 endPos > startPos + 1 &&
1487 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1488 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1494 if ( flags & LDAP_DN_SKIP ) {
1498 len = ( endPos ? endPos : p ) - startPos - escapes;
1500 if ( escapes == 0 ) {
1501 val->bv_val = LDAP_STRNDUP( startPos, len );
1506 val->bv_val = LDAP_MALLOC( len + 1 );
1507 for ( s = 0, d = 0; d < len; ) {
1508 if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1511 val->bv_val[ d++ ] = startPos[ s++ ];
1513 val->bv_val[ d ] = '\0';
1514 assert( strlen( val->bv_val ) == len );
1521 quotedIA52strval( const char *str, struct berval *val, const char **next, unsigned flags )
1523 const char *p, *startPos, *endPos = NULL;
1525 unsigned escapes = 0;
1533 /* initial quote already eaten */
1534 for ( startPos = p = str; p[ 0 ]; p++ ) {
1536 * According to RFC 1779, the quoted value can
1537 * contain escaped as well as unescaped special values;
1538 * as a consequence we tolerate escaped values
1539 * (e.g. '"\,"' -> '\,') and escape unescaped specials
1540 * (e.g. '","' -> '\,').
1542 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1543 if ( p[ 1 ] == '\0' ) {
1548 if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1549 && ( LDAP_DN_PEDANTIC & flags ) ) {
1551 * do we allow to escape normal chars?
1552 * LDAPv2 does not allow any mechanism
1553 * for escaping chars with '\' and hex
1560 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1562 /* eat closing quotes */
1568 * FIXME: can we accept anything else? I guess we need
1569 * to stop if a value is not legal
1573 if ( endPos == NULL ) {
1577 /* Strip trailing (unescaped) spaces */
1578 for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1583 if ( flags & LDAP_DN_SKIP ) {
1587 len = endPos - startPos - escapes;
1590 if ( escapes == 0 ) {
1591 val->bv_val = LDAP_STRNDUP( startPos, len );
1596 val->bv_val = LDAP_MALLOC( len + 1 );
1599 for ( s = d = 0; d < len; ) {
1600 if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1603 val->bv_val[ d++ ] = str[ s++ ];
1605 val->bv_val[ d ] = '\0';
1606 assert( strlen( val->bv_val ) == len );
1613 hexstr2bin( const char *str, char *c )
1623 if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1627 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c1 ) ) {
1630 assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) );
1637 if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1641 if ( LDAP_DN_ASCII_UCASE_HEXALPHA( c2 ) ) {
1642 *c += c2 - 'A' + 10;
1644 assert( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) );
1645 *c += c2 - 'a' + 10;
1653 hexstr2binval( const char *str, struct berval *val, const char **next, unsigned flags )
1655 const char *p, *startPos, *endPos = NULL;
1665 for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1666 switch ( LDAP_DN_FORMAT( flags ) ) {
1667 case LDAP_DN_FORMAT_LDAPV3:
1668 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1673 case LDAP_DN_FORMAT_LDAP:
1674 case LDAP_DN_FORMAT_LDAPV2:
1675 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1680 case LDAP_DN_FORMAT_DCE:
1681 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1687 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1688 if ( flags & LDAP_DN_PEDANTIC ) {
1693 for ( ; p[ 0 ]; p++ ) {
1694 switch ( LDAP_DN_FORMAT( flags ) ) {
1695 case LDAP_DN_FORMAT_LDAPV3:
1696 if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1701 case LDAP_DN_FORMAT_LDAP:
1702 case LDAP_DN_FORMAT_LDAPV2:
1703 if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1708 case LDAP_DN_FORMAT_DCE:
1709 if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1718 if ( !LDAP_DN_HEXPAIR( p ) ) {
1726 if ( flags & LDAP_DN_SKIP ) {
1730 len = ( ( endPos ? endPos : p ) - startPos ) / 2;
1732 assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
1735 val->bv_val = LDAP_MALLOC( len + 1 );
1736 if ( val->bv_val == NULL ) {
1737 return( LDAP_NO_MEMORY );
1740 for ( s = 0, d = 0; d < len; s += 2, d++ ) {
1743 hexstr2bin( &startPos[ s ], &c );
1745 val->bv_val[ d ] = c;
1748 val->bv_val[ d ] = '\0';
1754 * convert a byte in a hexadecimal pair
1757 byte2hexpair( const char *val, char *pair )
1759 static const char hexdig[] = "0123456789ABCDEF";
1765 * we assume the string has enough room for the hex encoding
1769 pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
1770 pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
1776 * convert a binary value in hexadecimal pairs
1779 binval2hexstr( struct berval *val, char *str )
1786 if ( val->bv_len == 0 ) {
1791 * we assume the string has enough room for the hex encoding
1795 for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
1796 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1803 * Length of the string representation, accounting for escaped hex
1807 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
1809 ber_len_t l, cl = 1;
1811 int escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3;
1812 #ifdef PRETTY_ESCAPE
1813 int escaped_ascii_len = LDAP_DN_IS_PRETTY( flags ) ? 2 : 3;
1814 #endif /* PRETTY_ESCAPE */
1820 if ( val->bv_len == 0 ) {
1824 for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
1825 cl = LDAP_UTF8_CHARLEN( p );
1827 /* illegal utf-8 char! */
1830 } else if ( cl > 1 ) {
1833 for ( cnt = 1; cnt < cl; cnt++ ) {
1834 if ( ( p[ cnt ] & 0x80 ) == 0x00 ) {
1838 l += escaped_byte_len * cl;
1840 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
1841 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1842 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
1843 #ifdef PRETTY_ESCAPE
1844 if ( LDAP_DN_WILLESCAPE_HEX( flags, p[ 0 ] ) ) {
1847 * there might be some chars we want
1848 * to escape in form of a couple
1849 * of hexdigits for optimization purposes
1854 l += escaped_ascii_len;
1856 #else /* ! PRETTY_ESCAPE */
1858 #endif /* ! PRETTY_ESCAPE */
1871 * convert to string representation, escaping with hex the UTF-8 stuff;
1872 * assume the destination has enough room for escaping
1875 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
1877 ber_len_t s, d, end;
1883 if ( val->bv_len == 0 ) {
1889 * we assume the string has enough room for the hex encoding
1892 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
1893 ber_len_t cl = LDAP_UTF8_CHARLEN( &val->bv_val[ s ] );
1896 * there might be some chars we want to escape in form
1897 * of a couple of hexdigits for optimization purposes
1899 if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) )
1900 #ifdef PRETTY_ESCAPE
1901 || LDAP_DN_WILLESCAPE_HEX( flags, val->bv_val[ s ] )
1902 #else /* ! PRETTY_ESCAPE */
1903 || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
1904 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
1905 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) )
1907 #endif /* ! PRETTY_ESCAPE */
1911 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1916 } else if ( cl > 1 ) {
1918 str[ d++ ] = val->bv_val[ s++ ];
1922 #ifdef PRETTY_ESCAPE
1923 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
1924 || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
1925 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
1927 if ( !LDAP_DN_IS_PRETTY( flags ) ) {
1928 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1934 #endif /* PRETTY_ESCAPE */
1935 str[ d++ ] = val->bv_val[ s++ ];
1945 * Length of the IA5 string representation (no UTF-8 allowed)
1948 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
1957 if ( val->bv_len == 0 ) {
1961 if ( flags & LDAP_AVA_NONPRINTABLE ) {
1963 * Turn value into a binary encoded BER
1968 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
1969 if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
1970 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1971 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
1986 * convert to string representation (np UTF-8)
1987 * assume the destination has enough room for escaping
1990 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
1992 ber_len_t s, d, end;
1998 if ( val->bv_len == 0 ) {
2003 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2005 * Turn value into a binary encoded BER
2012 * we assume the string has enough room for the hex encoding
2016 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2017 if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2018 || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2019 || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2022 str[ d++ ] = val->bv_val[ s++ ];
2032 * Length of the (supposedly) DCE string representation,
2033 * accounting for escaped hex of UTF-8 chars
2036 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2045 if ( val->bv_len == 0 ) {
2049 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2051 * FIXME: Turn the value into a binary encoded BER?
2056 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2057 if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2072 * convert to (supposedly) DCE string representation,
2073 * escaping with hex the UTF-8 stuff;
2074 * assume the destination has enough room for escaping
2077 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2085 if ( val->bv_len == 0 ) {
2090 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2092 * FIXME: Turn the value into a binary encoded BER?
2100 * we assume the string has enough room for the hex encoding
2104 for ( s = 0, d = 0; s < val->bv_len; ) {
2105 if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2108 str[ d++ ] = val->bv_val[ s++ ];
2118 * Length of the (supposedly) AD canonical string representation,
2119 * accounting for escaped hex of UTF-8 chars
2122 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2131 if ( val->bv_len == 0 ) {
2135 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2137 * FIXME: Turn the value into a binary encoded BER?
2142 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2143 if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2158 * convert to (supposedly) AD string representation,
2159 * escaping with hex the UTF-8 stuff;
2160 * assume the destination has enough room for escaping
2163 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2171 if ( val->bv_len == 0 ) {
2176 if ( flags & LDAP_AVA_NONPRINTABLE ) {
2178 * FIXME: Turn the value into a binary encoded BER?
2186 * we assume the string has enough room for the hex encoding
2190 for ( s = 0, d = 0; s < val->bv_len; ) {
2191 if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2194 str[ d++ ] = val->bv_val[ s++ ];
2204 * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2205 * the first part of the AD representation of the DN is written in DNS
2206 * form, i.e. dot separated domain name components (as suggested
2207 * by Luke Howard, http://www.padl.com/~lukeh)
2210 dn2domain( LDAPDN *dn, struct berval *bv, int pos, int *iRDN )
2213 int domain = 0, first = 1;
2214 ber_len_t l = 1; /* we move the null also */
2217 /* we are guaranteed there's enough memory in str */
2223 assert( *iRDN >= 0 );
2225 str = bv->bv_val + pos;
2227 for ( i = *iRDN; i >= 0; i-- ) {
2231 assert( dn[ 0 ][ i ] );
2234 assert( rdn[ 0 ][ 0 ] );
2235 ava = rdn[ 0 ][ 0 ];
2237 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2245 AC_MEMCPY( str, ava->la_value.bv_val,
2246 ava->la_value.bv_len + 1);
2247 l += ava->la_value.bv_len;
2250 AC_MEMCPY( str + ava->la_value.bv_len + 1, bv->bv_val, l);
2251 AC_MEMCPY( str, ava->la_value.bv_val,
2252 ava->la_value.bv_len );
2253 str[ ava->la_value.bv_len ] = '.';
2254 l += ava->la_value.bv_len + 1;
2259 bv->bv_len = pos + l - 1;
2265 rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
2266 int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2273 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2274 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2276 /* len(type) + '=' + '+' | ',' */
2277 l += ava->la_attr.bv_len + 2;
2279 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2280 /* octothorpe + twice the length */
2281 l += 1 + 2 * ava->la_value.bv_len;
2285 unsigned f = flags | ava->la_flags;
2287 if ( ( *s2l )( &ava->la_value, f, &vl ) ) {
2300 rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
2301 int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2306 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2307 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2309 AC_MEMCPY( &str[ l ], ava->la_attr.bv_val,
2310 ava->la_attr.bv_len );
2311 l += ava->la_attr.bv_len;
2315 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2317 if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2320 l += 2 * ava->la_value.bv_len;
2324 unsigned f = flags | ava->la_flags;
2326 if ( ( *s2s )( &ava->la_value, &str[ l ], f, &vl ) ) {
2331 str[ l++ ] = ( rdn[ 0 ][ iAVA + 1 ] ? '+' : ',' );
2340 rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2347 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2348 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2350 /* len(type) + '=' + ',' | '/' */
2351 l += ava->la_attr.bv_len + 2;
2353 switch ( ava->la_flags ) {
2354 case LDAP_AVA_BINARY:
2355 /* octothorpe + twice the length */
2356 l += 1 + 2 * ava->la_value.bv_len;
2359 case LDAP_AVA_STRING: {
2361 unsigned f = flags | ava->la_flags;
2363 if ( strval2DCEstrlen( &ava->la_value, f, &vl ) ) {
2381 rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2386 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2387 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2392 str[ l++ ] = ( iAVA ? ',' : '/' );
2395 AC_MEMCPY( &str[ l ], ava->la_attr.bv_val,
2396 ava->la_attr.bv_len );
2397 l += ava->la_attr.bv_len;
2401 switch ( ava->la_flags ) {
2402 case LDAP_AVA_BINARY:
2404 if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2407 l += 2 * ava->la_value.bv_len;
2410 case LDAP_AVA_STRING: {
2412 unsigned f = flags | ava->la_flags;
2414 if ( strval2DCEstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2432 rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2442 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2443 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2446 l += ( rdn[ 0 ][ iAVA + 1 ] ? 3 : 2 );
2448 /* FIXME: are binary values allowed in UFN? */
2449 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2450 /* octothorpe + twice the value */
2451 l += 1 + 2 * ava->la_value.bv_len;
2455 unsigned f = flags | ava->la_flags;
2457 if ( strval2strlen( &ava->la_value, f, &vl ) ) {
2470 rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
2475 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2476 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2478 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2480 if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2483 l += 2 * ava->la_value.bv_len;
2487 unsigned f = flags | ava->la_flags;
2489 if ( strval2str( &ava->la_value, &str[ l ], f, &vl ) ) {
2495 if ( rdn[ 0 ][ iAVA + 1 ]) {
2496 AC_MEMCPY( &str[ l ], " + ", 3 );
2500 AC_MEMCPY( &str[ l ], ", ", 2 );
2511 rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2521 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2522 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2527 /* FIXME: are binary values allowed in UFN? */
2528 switch ( ava->la_flags ) {
2529 case LDAP_AVA_BINARY:
2530 /* octothorpe + twice the value */
2531 l += 1 + 2 * ava->la_value.bv_len;
2534 case LDAP_AVA_STRING: {
2536 unsigned f = flags | ava->la_flags;
2538 if ( strval2ADstrlen( &ava->la_value, f, &vl ) ) {
2556 rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2561 for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
2562 LDAPAVA *ava = rdn[ 0 ][ iAVA ];
2567 str[ l++ ] = ( iAVA ? ',' : '/' );
2570 switch ( ava->la_flags ) {
2571 case LDAP_AVA_BINARY:
2573 if ( binval2hexstr( &ava->la_value, &str[ l ] ) ) {
2576 l += 2 * ava->la_value.bv_len;
2579 case LDAP_AVA_STRING: {
2581 unsigned f = flags | ava->la_flags;
2583 if ( strval2ADstr( &ava->la_value, &str[ l ], f, &vl ) ) {
2603 * Returns in str a string representation of rdn based on flags.
2604 * There is some duplication of code between this and ldap_dn2str;
2605 * this is wanted to reduce the allocation of temporary buffers.
2608 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2615 rc = ldap_rdn2bv( rdn, &bv, flags );
2621 ldap_rdn2bv( LDAPRDN *rdn, struct berval *bv, unsigned flags )
2631 if ( rdn == NULL ) {
2632 bv->bv_val = LDAP_STRDUP( "" );
2633 return( LDAP_SUCCESS );
2637 * This routine wastes "back" bytes at the end of the string
2640 switch ( LDAP_DN_FORMAT( flags ) ) {
2641 case LDAP_DN_FORMAT_LDAPV3:
2642 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2643 return( LDAP_OTHER );
2647 case LDAP_DN_FORMAT_LDAPV2:
2648 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2649 return( LDAP_OTHER );
2653 case LDAP_DN_FORMAT_UFN:
2654 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2655 return( LDAP_OTHER );
2659 case LDAP_DN_FORMAT_DCE:
2660 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2661 return( LDAP_OTHER );
2665 case LDAP_DN_FORMAT_AD_CANONICAL:
2666 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2667 return( LDAP_OTHER );
2672 return( LDAP_INVALID_DN_SYNTAX );
2675 bv->bv_val = LDAP_MALLOC( l + 1 );
2677 switch ( LDAP_DN_FORMAT( flags ) ) {
2678 case LDAP_DN_FORMAT_LDAPV3:
2679 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2str );
2683 case LDAP_DN_FORMAT_LDAPV2:
2684 rc = rdn2str( rdn, bv->bv_val, flags, &l, strval2IA5str );
2688 case LDAP_DN_FORMAT_UFN:
2689 rc = rdn2UFNstr( rdn, bv->bv_val, flags, &l );
2693 case LDAP_DN_FORMAT_DCE:
2694 rc = rdn2DCEstr( rdn, bv->bv_val, flags, &l, 1 );
2698 case LDAP_DN_FORMAT_AD_CANONICAL:
2699 rc = rdn2ADstr( rdn, bv->bv_val, flags, &l, 1 );
2704 /* need at least one of the previous */
2705 return( LDAP_OTHER );
2709 ldap_memfree( bv->bv_val );
2710 return( LDAP_OTHER );
2713 bv->bv_len = l - back;
2714 bv->bv_val[ bv->bv_len ] = '\0';
2716 return( LDAP_SUCCESS );
2720 * Very bulk implementation; many optimizations can be performed
2721 * - a NULL dn results in an empty string ""
2724 * a) what do we do if a UTF-8 string must be converted in LDAPv2?
2725 * we must encode it in binary form ('#' + HEXPAIRs)
2726 * b) does DCE/AD support UTF-8?
2727 * no clue; don't think so.
2728 * c) what do we do when binary values must be converted in UTF/DCE/AD?
2729 * use binary encoded BER
2731 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
2738 rc = ldap_dn2bv( dn, &bv, flags );
2743 int ldap_dn2bv( LDAPDN *dn, struct berval *bv, unsigned flags )
2746 int rc = LDAP_OTHER;
2749 /* stringifying helpers for LDAPv3/LDAPv2 */
2750 int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2751 int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2758 Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2bv(%u)\n%s%s", flags, "", "" );
2761 * a null dn means an empty dn string
2762 * FIXME: better raise an error?
2765 bv->bv_val = LDAP_STRDUP( "" );
2766 return( LDAP_SUCCESS );
2769 switch ( LDAP_DN_FORMAT( flags ) ) {
2770 case LDAP_DN_FORMAT_LDAPV3:
2771 sv2l = strval2strlen;
2775 case LDAP_DN_FORMAT_LDAPV2:
2776 sv2l = strval2IA5strlen;
2777 sv2s = strval2IA5str;
2780 for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
2782 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
2784 if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
2785 goto return_results;
2791 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2792 rc = LDAP_NO_MEMORY;
2796 for ( l = 0, iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
2798 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
2800 if ( rdn2str( rdn, &bv->bv_val[ l ], flags,
2802 LDAP_FREE( bv->bv_val );
2804 goto return_results;
2812 * trim the last ',' (the allocated memory
2813 * is one byte longer than required)
2815 bv->bv_len = len - 1;
2816 bv->bv_val[ bv->bv_len ] = '\0';
2821 case LDAP_DN_FORMAT_UFN: {
2824 * FIXME: quoting from RFC 1781:
2826 To take a distinguished name, and generate a name of this format with
2827 attribute types omitted, the following steps are followed.
2829 1. If the first attribute is of type CommonName, the type may be
2832 2. If the last attribute is of type Country, the type may be
2835 3. If the last attribute is of type Country, the last
2836 Organisation attribute may have the type omitted.
2838 4. All attributes of type OrganisationalUnit may have the type
2839 omitted, unless they are after an Organisation attribute or
2840 the first attribute is of type OrganisationalUnit.
2842 * this should be the pedantic implementation.
2844 * Here the standard implementation reflects
2845 * the one historically provided by OpenLDAP
2846 * (and UMIch, I presume), with the variant
2847 * of spaces and plusses (' + ') separating
2850 * A non-standard but nice implementation could
2851 * be to turn the final "dc" attributes into a
2852 * dot-separated domain.
2854 * Other improvements could involve the use of
2855 * friendly country names and so.
2858 int leftmost_dc = -1;
2860 #endif /* DC_IN_UFN */
2862 for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
2864 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
2866 if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
2867 goto return_results;
2872 if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
2873 if ( leftmost_dc == -1 ) {
2879 #endif /* DC_IN_UFN */
2882 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2883 rc = LDAP_NO_MEMORY;
2888 if ( leftmost_dc == -1 ) {
2889 #endif /* DC_IN_UFN */
2890 for ( l = 0, iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
2892 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
2894 if ( rdn2UFNstr( rdn, &bv->bv_val[ l ],
2896 LDAP_FREE( bv->bv_val );
2898 goto return_results;
2904 * trim the last ', ' (the allocated memory
2905 * is two bytes longer than required)
2907 bv->bv_len = len - 2;
2908 bv->bv_val[ bv->bv_len ] = '\0';
2911 last_iRDN = iRDN - 1;
2913 for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
2915 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
2917 if ( rdn2UFNstr( rdn, &bv->bv_val[ l ],
2919 LDAP_FREE( bv->bv_val );
2921 goto return_results;
2926 if ( !dn2domain( dn, bv, l, &last_iRDN ) ) {
2927 LDAP_FREE( bv->bv_val );
2929 goto return_results;
2932 /* the string is correctly terminated by dn2domain */
2934 #endif /* DC_IN_UFN */
2940 case LDAP_DN_FORMAT_DCE:
2942 for ( iRDN = 0, len = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
2944 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
2946 if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
2947 goto return_results;
2953 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2954 rc = LDAP_NO_MEMORY;
2958 for ( l = 0; iRDN--; ) {
2960 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
2962 if ( rdn2DCEstr( rdn, &bv->bv_val[ l ], flags,
2964 LDAP_FREE( bv->bv_val );
2966 goto return_results;
2974 bv->bv_val[ bv->bv_len ] = '\0';
2979 case LDAP_DN_FORMAT_AD_CANONICAL: {
2982 * Sort of UFN for DCE DNs: a slash ('/') separated
2983 * global->local DN with no types; strictly speaking,
2984 * the naming context should be a domain, which is
2985 * written in DNS-style, e.g. dot-deparated.
2989 * "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
2993 * "microsoft.com/People/Bill,Gates"
2995 for ( iRDN = 0, len = -1; dn[ 0 ][ iRDN ]; iRDN++ ) {
2997 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
2999 if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
3000 goto return_results;
3006 if ( ( bv->bv_val = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3007 rc = LDAP_NO_MEMORY;
3012 if ( iRDN && dn2domain( dn, bv, 0, &iRDN ) ) {
3013 for ( l = bv->bv_len; iRDN >= 0 ; iRDN-- ) {
3015 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
3017 if ( rdn2ADstr( rdn, &bv->bv_val[ l ],
3018 flags, &rdnl, 0 ) ) {
3019 LDAP_FREE( bv->bv_val );
3021 goto return_results;
3030 * Strictly speaking, AD canonical requires
3031 * a DN to be in the form "..., dc=smtg",
3032 * i.e. terminated by a domain component
3034 if ( flags & LDAP_DN_PEDANTIC ) {
3035 LDAP_FREE( bv->bv_val );
3037 rc = LDAP_INVALID_DN_SYNTAX;
3041 for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3043 LDAPRDN *rdn = dn[ 0 ][ iRDN ];
3045 if ( rdn2ADstr( rdn, &bv->bv_val[ l ],
3046 flags, &rdnl, first ) ) {
3047 LDAP_FREE( bv->bv_val );
3049 goto return_results;
3059 bv->bv_val[ bv->bv_len ] = '\0';
3066 return( LDAP_INVALID_DN_SYNTAX );
3070 Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2bv(%s,%u)=%d\n", bv->bv_val, flags, rc );