]> git.sur5r.net Git - openldap/blob - libraries/libldap/getdn.c
21980226d1e54f24d836e47f01d2816b31bec7e9
[openldap] / libraries / libldap / getdn.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*  Portions
7  *  Copyright (c) 1994 Regents of the University of Michigan.
8  *  All rights reserved.
9  *
10  *  getdn.c
11  */
12
13 #include "portable.h"
14
15 #include <stdio.h>
16
17 #include <ac/stdlib.h>
18
19 #include <ac/ctype.h>
20 #include <ac/socket.h>
21 #include <ac/string.h>
22 #include <ac/time.h>
23
24 #include "ldap-int.h"
25
26 /* extension to UFN that turns trailing "dc=value" rdns in DNS style,
27  * e.g. "ou=People,dc=openldap,dc=org" => "People, openldap.org" */
28 #define DC_IN_UFN
29
30 static int dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout );
31
32 /* from libraries/libldap/schema.c */
33 extern char * parse_numericoid(const char **sp, int *code, const int flags);
34
35 /* parsing/printing routines */
36 static int str2strval( const char *str, struct berval **val, 
37                 const char **next, unsigned flags, unsigned *retFlags );
38 static int DCE2strval( const char *str, struct berval **val, 
39                 const char **next, unsigned flags );
40 static int IA52strval( const char *str, struct berval **val, 
41                 const char **next, unsigned flags );
42 static int quotedIA52strval( const char *str, struct berval **val, 
43                 const char **next, unsigned flags );
44 static int hexstr2binval( const char *str, struct berval **val, 
45                 const char **next, unsigned flags );
46 static int hexstr2bin( const char *str, char *c );
47 static int byte2hexpair( const char *val, char *pair );
48 static int binval2hexstr( struct berval *val, char *str );
49 static int strval2strlen( struct berval *val, unsigned flags, 
50                 ber_len_t *len );
51 static int strval2str( struct berval *val, char *str, unsigned flags, 
52                 ber_len_t *len );
53 static int strval2IA5strlen( struct berval *val, unsigned flags,
54                 ber_len_t *len );
55 static int strval2IA5str( struct berval *val, char *str, unsigned flags, 
56                 ber_len_t *len );
57 static int strval2DCEstrlen( struct berval *val, unsigned flags,
58                 ber_len_t *len );
59 static int strval2DCEstr( struct berval *val, char *str, unsigned flags, 
60                 ber_len_t *len );
61 static int strval2ADstrlen( struct berval *val, unsigned flags,
62                 ber_len_t *len );
63 static int strval2ADstr( struct berval *val, char *str, unsigned flags, 
64                 ber_len_t *len );
65 static int dn2domain( LDAPDN *dn, char *str, int *iRDN );
66
67 /* AVA helpers */
68 static LDAPAVA * ldapava_new(
69         const struct berval *attr, const struct berval *val, unsigned flags );
70 static LDAPRDN * ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava );
71 static LDAPRDN * ldapava_insert_into_rdn(
72         LDAPRDN *rdn, LDAPAVA *ava, unsigned where );
73 static LDAPDN * ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn );
74 static LDAPDN * ldapava_insert_into_dn(
75         LDAPDN *dn, LDAPRDN *rdn, unsigned where );
76
77 /* Higher level helpers */
78 static int rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
79                 int ( *s2l )( struct berval *, unsigned, ber_len_t * ) );
80 static int rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
81                 int ( *s2s )( struct berval *, char *, unsigned, ber_len_t * ));
82 static int rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len  );
83 static int rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len );
84 static int rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
85 static int rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flag, ber_len_t *len, int first );
86 static int rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len );
87 static int rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first );
88
89 /*
90  * RFC 1823 ldap_get_dn
91  */
92 char *
93 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
94 {
95         char            *dn;
96         BerElement      tmp;
97
98         Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
99
100         if ( entry == NULL ) {
101                 ld->ld_errno = LDAP_PARAM_ERROR;
102                 return( NULL );
103         }
104
105         tmp = *entry->lm_ber;   /* struct copy */
106         if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
107                 ld->ld_errno = LDAP_DECODING_ERROR;
108                 return( NULL );
109         }
110
111         return( dn );
112 }
113
114 /*
115  * RFC 1823 ldap_dn2ufn
116  */
117 char *
118 ldap_dn2ufn( LDAP_CONST char *dn )
119 {
120         char    *out = NULL;
121
122         Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
123
124         ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_UFN );
125         
126         return( out );
127 }
128
129 /*
130  * RFC 1823 ldap_explode_dn
131  */
132 char **
133 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
134 {
135         LDAPDN  *tmpDN;
136         char    **values = NULL;
137         int     iRDN;
138         unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
139         
140         Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
141
142         if ( ldap_str2dn( dn, &tmpDN, LDAP_DN_FORMAT_LDAP ) 
143                         != LDAP_SUCCESS ) {
144                 return NULL;
145         }
146
147         if( tmpDN == NULL ) {
148                 values = LDAP_MALLOC( sizeof( char * ) );
149                 if( values == NULL ) return NULL;
150
151                 values[0] = NULL;
152                 return values;
153         }
154
155         for ( iRDN = 0; tmpDN[ iRDN ]; iRDN++ ) {
156                 char    *str, **v = NULL;
157                 
158                 ldap_rdn2str( tmpDN[ iRDN ][ 0 ], &str, flag );
159
160                 v = LDAP_REALLOC( values, sizeof( char * ) * ( iRDN + 1 ) );
161                 if ( v == NULL ) {
162                         LBER_VFREE( values );
163                         ldap_dnfree( tmpDN );
164                         return NULL;
165                 }
166                 values = v;
167                 values[ iRDN ] = str;
168         }
169
170         values[ iRDN ] = NULL;
171         return values;
172 }
173
174 char **
175 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
176 {
177         LDAPDN  *tmpDN;
178         char    **values = NULL;
179         int     iAVA;
180         unsigned flag = notypes ? LDAP_DN_FORMAT_UFN : LDAP_DN_FORMAT_LDAPV3;
181         
182         Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
183
184         /*
185          * we assume this dn is made of one rdn only
186          */
187         if ( ldap_str2dn( rdn, &tmpDN, LDAP_DN_FORMAT_LDAP ) 
188                         != LDAP_SUCCESS ) {
189                 return( NULL );
190         }
191
192         for ( iAVA = 0; tmpDN[ 0 ][ 0 ][ iAVA ]; iAVA++ ) {
193                 ber_len_t       l = 0, vl, al = 0;
194                 char            *str, **v = NULL;
195                 LDAPAVA         *ava = tmpDN[ 0 ][ 0 ][ iAVA ][ 0 ];
196                 
197                 v = LDAP_REALLOC( values, sizeof( char * ) * ( 2 + iAVA ) );
198                 if ( v == NULL ) {
199                         goto error_return;
200                 }
201                 values = v;
202                 
203                 if ( ava->la_flags == LDAP_AVA_BINARY ) {
204                         vl = 1 + 2 * ava->la_value->bv_len;
205
206                 } else {
207                         if ( strval2strlen( ava->la_value, 
208                                                 ava->la_flags, &vl ) ) {
209                                 goto error_return;
210                         }
211                 }
212                 
213                 if ( !notypes ) {
214                         al = ava->la_attr->bv_len;
215                         l = vl + ava->la_attr->bv_len + 1;
216
217                         str = LDAP_MALLOC( l + 1 );
218                         AC_MEMCPY( str, ava->la_attr->bv_val, 
219                                         ava->la_attr->bv_len );
220                         str[ al++ ] = '=';
221
222                 } else {
223                         l = vl;
224                         str = LDAP_MALLOC( l + 1 );
225                 }
226                 
227                 if ( ava->la_flags == LDAP_AVA_BINARY ) {
228                         str[ al++ ] = '#';
229                         if ( binval2hexstr( ava->la_value, &str[ al ] ) ) {
230                                 goto error_return;
231                         }
232
233                 } else {
234                         if ( strval2str( ava->la_value, &str[ al ], 
235                                         ava->la_flags, &vl ) ) {
236                                 goto error_return;
237                         }
238                 }
239
240                 str[ l ] = '\0';
241                 values[ iAVA ] = str;
242         }
243         values[ iAVA ] = NULL;
244
245         ldap_dnfree( tmpDN );
246
247         return( values );
248
249 error_return:;
250         LBER_VFREE( values );
251         ldap_dnfree( tmpDN );
252         return( NULL );
253 }
254
255 char *
256 ldap_dn2dcedn( LDAP_CONST char *dn )
257 {
258         char    *out = NULL;
259
260         Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
261
262         ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, &out, LDAP_DN_FORMAT_DCE );
263
264         return( out );
265 }
266
267 char *
268 ldap_dcedn2dn( LDAP_CONST char *dce )
269 {
270         char    *out = NULL;
271
272         Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
273
274         ( void )dn2dn( dce, LDAP_DN_FORMAT_DCE, &out, LDAP_DN_FORMAT_LDAPV3 );
275
276         return( out );
277 }
278
279 char *
280 ldap_dn2ad_canonical( LDAP_CONST char *dn )
281 {
282         char    *out = NULL;
283
284         Debug( LDAP_DEBUG_TRACE, "ldap_dn2ad_canonical\n", 0, 0, 0 );
285
286         ( void )dn2dn( dn, LDAP_DN_FORMAT_LDAP, 
287                        &out, LDAP_DN_FORMAT_AD_CANONICAL );
288
289         return( out );
290 }
291
292 int
293 ldap_dn_normalize( const char *in, unsigned iflags, char **out, unsigned oflags ) 
294 {
295         assert( out );
296
297         Debug( LDAP_DEBUG_TRACE, "ldap_dn_normalize\n", 0, 0, 0 );
298
299         return dn2dn( in, iflags, out, oflags);
300 }
301
302 /*
303  * helper that changes the string representation of dnin
304  * from ( fin & LDAP_DN_FORMAT_MASK ) to ( fout & LDAP_DN_FORMAT_MASK )
305  * 
306  * fin can be one of:
307  *      LDAP_DN_FORMAT_LDAP             (rfc 2253 and ldapbis liberal, 
308  *                                      plus some rfc 1779)
309  *      LDAP_DN_FORMAT_LDAPV3           (rfc 2253 and ldapbis)
310  *      LDAP_DN_FORMAT_LDAPV2           (rfc 1779)
311  *      LDAP_DN_FORMAT_DCE              (?)
312  *
313  * fout can be any of the above except
314  *      LDAP_DN_FORMAT_LDAP
315  * plus:
316  *      LDAP_DN_FORMAT_UFN              (rfc 1781, partial and with extensions)
317  *      LDAP_DN_FORMAT_AD_CANONICAL     (?)
318  */
319 static int
320 dn2dn( const char *dnin, unsigned fin, char **dnout, unsigned fout )
321 {
322         int     rc;
323         LDAPDN  *tmpDN = NULL;
324
325         assert( dnout );
326
327         *dnout = NULL;
328
329         if ( dnin == NULL ) {
330                 return( LDAP_SUCCESS );
331         }
332
333         rc = ldap_str2dn( dnin , &tmpDN, fin );
334         if ( rc != LDAP_SUCCESS ) {
335                 return( rc );
336         }
337
338         rc = ldap_dn2str( tmpDN, dnout, fout );
339
340         ldap_dnfree( tmpDN );
341
342         return( rc );
343 }
344
345 /* States */
346 #define B4AVA                   0x0000
347
348 /* #define      B4ATTRTYPE              0x0001 */
349 #define B4OIDATTRTYPE           0x0002
350 #define B4STRINGATTRTYPE        0x0003
351
352 #define B4AVAEQUALS             0x0100
353 #define B4AVASEP                0x0200
354 #define B4RDNSEP                0x0300
355 #define GOTAVA                  0x0400
356
357 #define B4ATTRVALUE             0x0010
358 #define B4STRINGVALUE           0x0020
359 #define B4IA5VALUEQUOTED        0x0030
360 #define B4IA5VALUE              0x0040
361 #define B4BINARYVALUE           0x0050
362
363 /* Helpers (mostly from slapd.h; maybe it should be rewritten from this) */
364 #define LDAP_DN_ASCII_SPACE(c) \
365         ( (c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' )
366 #define LDAP_DN_ASCII_LOWER(c)          ( (c) >= 'a' && (c) <= 'z' )
367 #define LDAP_DN_ASCII_UPPER(c)          ( (c) >= 'A' && (c) <= 'Z' )
368 #define LDAP_DN_ASCII_ALPHA(c) \
369         ( LDAP_DN_ASCII_LOWER(c) || LDAP_DN_ASCII_UPPER(c) )
370 #define LDAP_DN_ASCII_DIGIT(c)          ( (c) >= '0' && (c) <= '9' )
371 #define LDAP_DN_ASCII_LCASE_HEXALPHA(c) ( (c) >= 'a' && (c) <= 'f' )
372 #define LDAP_DN_ASCII_UCASE_HEXALPHA(c) ( (c) >= 'A' && (c) <= 'F' )
373 #define LDAP_DN_ASCII_HEXDIGIT(c) \
374         ( LDAP_DN_ASCII_DIGIT(c) \
375           || LDAP_DN_ASCII_LCASE_HEXALPHA(c) \
376           || LDAP_DN_ASCII_UCASE_HEXALPHA(c) )
377 #define LDAP_DN_ASCII_ALNUM(c) \
378         ( LDAP_DN_ASCII_ALPHA(c) || LDAP_DN_ASCII_DIGIT(c) )
379 #define LDAP_DN_ASCII_PRINTABLE(c)      ( (c) >= ' ' && (c) <= '~' )
380
381 /* attribute type */
382 #define LDAP_DN_OID_LEADCHAR(c)         ( LDAP_DN_ASCII_DIGIT(c) )
383 #define LDAP_DN_DESC_LEADCHAR(c)        ( LDAP_DN_ASCII_ALPHA(c) )
384 #define LDAP_DN_DESC_CHAR(c)            ( LDAP_DN_ASCII_ALNUM(c) || (c) == '-' )
385 #define LDAP_DN_LANG_SEP(c)             ( (c) == ';' )
386 #define LDAP_DN_ATTRDESC_CHAR(c) \
387         ( LDAP_DN_DESC_CHAR(c) || LDAP_DN_LANG_SEP(c) )
388
389 /* special symbols */
390 #define LDAP_DN_AVA_EQUALS(c)           ( (c) == '=' )
391 #define LDAP_DN_AVA_SEP(c)              ( (c) == '+' )
392 #define LDAP_DN_RDN_SEP(c)              ( (c) == ',' )
393 #define LDAP_DN_RDN_SEP_V2(c)           ( LDAP_DN_RDN_SEP(c) || (c) == ';' )
394 #define LDAP_DN_OCTOTHORPE(c)           ( (c) == '#' )
395 #define LDAP_DN_QUOTES(c)               ( (c) == '\"' )
396 #define LDAP_DN_ESCAPE(c)               ( (c) == '\\' )
397 #define LDAP_DN_VALUE_END(c) \
398         ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
399 #define LDAP_DN_NE(c) \
400         ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \
401           || LDAP_DN_QUOTES(c) || (c) == '<' || (c) == '>' )
402 #define LDAP_DN_NEEDESCAPE(c) \
403         ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) )
404 #define LDAP_DN_NEEDESCAPE_LEAD(c) \
405         ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) || LDAP_DN_NE(c) )
406 #define LDAP_DN_NEEDESCAPE_TRAIL(c) \
407         ( LDAP_DN_ASCII_SPACE(c) || LDAP_DN_NEEDESCAPE(c) )
408 #define LDAP_DN_WILLESCAPE_CHAR( c) \
409         ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) )
410 #define LDAP_DN_IS_PRETTY( f )          ( (f) & LDAP_DN_PRETTY )
411 #define LDAP_DN_WILLESCAPE(f, c) \
412         ( ( !LDAP_DN_IS_PRETTY( f ) ) && LDAP_DN_WILLESCAPE_CHAR(c) )
413
414 /* LDAPv2 */
415 #define LDAP_DN_VALUE_END_V2(c) \
416         ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) )
417 /* RFC 1779 */
418 #define LDAP_DN_V2_SPECIAL(c) \
419           ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_EQUALS(c) \
420             || LDAP_DN_AVA_SEP(c) || (c) == '<' || (c) == '>' \
421             || LDAP_DN_OCTOTHORPE(c) )
422 #define LDAP_DN_V2_PAIR(c) \
423           ( LDAP_DN_V2_SPECIAL(c) || LDAP_DN_ESCAPE(c) || LDAP_DN_QUOTES(c) )
424
425 /*
426  * DCE (mostly from Luke Howard and IBM implementation for AIX)
427  *
428  * From: "Application Development Guide - Directory Services" (FIXME: add link?)
429  * Here escapes and valid chars for GDS are considered; as soon as more
430  * specific info is found, the macros will be updated.
431  *
432  * Chars:       'a'-'z', 'A'-'Z', '0'-'9', 
433  *              '.', ':', ',', ''', '+', '-', '=', '(', ')', '?', '/', ' '.
434  *
435  * Metachars:   '/', ',', '=', '\'.
436  *
437  * the '\' is used to escape other metachars.
438  *
439  * Assertion:           '='
440  * RDN separator:       '/'
441  * AVA separator:       ','
442  * 
443  * Attribute types must start with alphabetic chars and can contain 
444  * alphabetic chars and digits (FIXME: no '-'?). OIDs are allowed.
445  */
446 #define LDAP_DN_RDN_SEP_DCE(c)          ( (c) == '/' )
447 #define LDAP_DN_AVA_SEP_DCE(c)          ( (c) == ',' )
448 #define LDAP_DN_ESCAPE_DCE(c)           ( LDAP_DN_ESCAPE(c) )
449 #define LDAP_DN_VALUE_END_DCE(c) \
450         ( LDAP_DN_RDN_SEP_DCE(c) || LDAP_DN_AVA_SEP_DCE(c) )
451 #define LDAP_DN_NEEDESCAPE_DCE(c) \
452         ( LDAP_DN_VALUE_END_DCE(c) || LDAP_DN_AVA_EQUALS(c) )
453
454 /* AD Canonical */
455 #define LDAP_DN_RDN_SEP_AD(c)           ( (c) == '/' )
456 #define LDAP_DN_ESCAPE_AD(c)            ( LDAP_DN_ESCAPE(c) )
457 #define LDAP_DN_AVA_SEP_AD(c)           ( (c) == ',' )  /* assume same as DCE */
458 #define LDAP_DN_VALUE_END_AD(c) \
459         ( LDAP_DN_RDN_SEP_AD(c) || LDAP_DN_AVA_SEP_AD(c) )
460 #define LDAP_DN_NEEDESCAPE_AD(c) \
461         ( LDAP_DN_VALUE_END_AD(c) || LDAP_DN_AVA_EQUALS(c) )
462
463 /* generics */
464 #define LDAP_DN_HEXPAIR(s) \
465         ( LDAP_DN_ASCII_HEXDIGIT((s)[0]) && LDAP_DN_ASCII_HEXDIGIT((s)[1]) )
466 #define LDAP_DC_ATTR                    "dc"
467 /* better look at the AttributeDescription? */
468
469 /* FIXME: no composite rdn or non-"dc" types, right?
470  * (what about "dc" in OID form?) */
471 /* FIXME: we do not allow binary values in domain, right? */
472 /* NOTE: use this macro only when ABSOLUTELY SURE rdn IS VALID! */
473 #define LDAP_DN_IS_RDN_DC( rdn ) \
474         ( ( rdn ) && ( rdn )[ 0 ][ 0 ] && !( rdn )[ 1 ] \
475           && ( ( rdn )[ 0 ][ 0 ]->la_flags == LDAP_AVA_STRING ) \
476           && ! strcasecmp( ( rdn )[ 0 ][ 0 ]->la_attr->bv_val, LDAP_DC_ATTR ) )
477
478 /* Composite rules */
479 #define LDAP_DN_ALLOW_ONE_SPACE(f) \
480         ( LDAP_DN_LDAPV2(f) \
481           || !( (f) & LDAP_DN_P_NOSPACEAFTERRDN ) )
482 #define LDAP_DN_ALLOW_SPACES(f) \
483         ( LDAP_DN_LDAPV2(f) \
484           || !( (f) & ( LDAP_DN_P_NOLEADTRAILSPACES | LDAP_DN_P_NOSPACEAFTERRDN ) ) )
485 #define LDAP_DN_LDAP(f) \
486         ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAP )
487 #define LDAP_DN_LDAPV3(f) \
488         ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV3 )
489 #define LDAP_DN_LDAPV2(f) \
490         ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_LDAPV2 )
491 #define LDAP_DN_DCE(f) \
492         ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_DCE )
493 #define LDAP_DN_UFN(f) \
494         ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_UFN )
495 #define LDAP_DN_ADC(f) \
496         ( ( (f) & LDAP_DN_FORMAT_MASK ) == LDAP_DN_FORMAT_AD_CANONICAL )
497 #define LDAP_DN_FORMAT(f)               ( (f) & LDAP_DN_FORMAT_MASK )
498
499 /*
500  * LDAPAVA helpers (will become part of the API for operations 
501  * on structural representations of DNs).
502  */
503 LDAPAVA *
504 ldapava_new( const struct berval *attr, const struct berval *val, 
505                 unsigned flags )
506 {
507         LDAPAVA *ava;
508
509         assert( attr );
510         assert( val );
511
512         ava = LDAP_MALLOC( sizeof( LDAPAVA ) );
513         
514         /* should we test it? */
515         if ( ava == NULL ) {
516                 return( NULL );
517         }
518
519         ava->la_attr = ( struct berval * )attr;
520         ava->la_value = ( struct berval * )val;
521         ava->la_flags = flags;
522
523         ava->la_private = NULL;
524
525         return( ava );
526 }
527
528 void
529 ldap_avafree( LDAPAVA *ava )
530 {
531         assert( ava );
532
533 #if 0
534         /* ava's private must be freed by caller */
535         assert( ava->la_private != NULL );
536 #endif
537
538         ber_bvfree( ava->la_attr );
539         ber_bvfree( ava->la_value );
540
541         LDAP_FREE( ava );
542 }
543
544 LDAPRDN *
545 ldapava_append_to_rdn( LDAPRDN *rdn, LDAPAVA *ava )
546 {
547         LDAPRDN         *newRDN;
548         unsigned        i = 0U;
549
550         assert( ava );
551
552         if ( rdn != NULL ) {
553                 for ( i = 0U; rdn[ i ]; i++ ) {
554                         /* no op */
555                 }
556         }
557         newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
558         newRDN[ i ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
559         newRDN[ i ][ 0 ] = ava;
560         newRDN[ i + 1 ] = NULL;
561
562         return( newRDN );
563 }
564
565 LDAPRDN *
566 ldapava_insert_into_rdn( LDAPRDN *rdn, LDAPAVA *ava, unsigned where )
567 {
568         LDAPRDN         *newRDN;
569         unsigned        i = 0U;
570
571         assert( ava );
572
573         if ( rdn != NULL ) {
574                 for ( i = 0U; rdn[ i ]; i++ ) {
575                         /* no op */
576                 }
577         }
578         if ( where > i ) {
579                 where = i;
580                 /* assume "at end", which corresponds to
581                  * ldapava_append_to_rdn */
582         }
583         
584         newRDN = LDAP_REALLOC( rdn, ( i + 2 ) * sizeof( LDAPAVA ** ) );
585         
586         /* data after insert point */
587         AC_MEMCPY( &newRDN[ where + 1 ], &newRDN[ where ],
588                         ( i - where ) * sizeof( LDAPRDN * ) );
589
590         newRDN[ where ] = LDAP_MALLOC( sizeof( LDAPAVA * ) );
591         newRDN[ where ][ 0 ] = ava;
592         newRDN[ i + 1 ] = NULL;
593
594         return( newRDN );
595 }
596
597 void
598 ldap_rdnfree( LDAPRDN *rdn )
599 {
600         int iAVA;
601         
602         if ( rdn == NULL ) {
603                 return;
604         }
605
606         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
607                 assert( rdn[ iAVA ][ 0 ] );
608
609                 ldap_avafree( rdn[ iAVA ][ 0 ] );
610         }
611
612         LDAP_VFREE( rdn );
613 }
614
615 LDAPDN *
616 ldapava_append_to_dn( LDAPDN *dn, LDAPRDN *rdn )
617 {
618         LDAPDN          *newDN;
619         unsigned        i = 0U;
620
621         assert( rdn );
622
623         if ( dn != NULL ) {
624                 for ( i = 0U; dn[ i ]; i++ ) {
625                         /* no op */
626                 }
627         }
628         newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
629         newDN[ i ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
630         newDN[ i ][ 0 ] = rdn;
631         newDN[ i + 1 ] = NULL;
632
633         return( newDN );
634 }
635
636 LDAPDN *
637 ldapava_insert_into_dn( LDAPDN *dn, LDAPRDN *rdn, unsigned where )
638 {
639         LDAPDN          *newDN;
640         unsigned        i = 0U;
641
642         assert( rdn );
643
644         if ( dn != NULL ) {
645                 for ( i = 0U; dn[ i ]; i++ ) {
646                         /* no op */
647                 }
648         }
649         if ( where > i ) {
650                 where = i;
651                 /* assume "at end", which corresponds to
652                  * ldapava_append_to_dn */
653         }
654         
655         newDN = LDAP_REALLOC( dn, ( i + 2 ) * sizeof( LDAPRDN ** ) );
656         
657         /* data after insert point */
658         AC_MEMCPY( &newDN[ where + 1 ], &newDN[ where ],
659                         ( i - where ) * sizeof( LDAPDN * ) );
660
661         newDN[ where ] = LDAP_MALLOC( sizeof( LDAPRDN * ) );
662         newDN[ where ][ 0 ] = rdn;
663         newDN[ i + 1 ] = NULL;
664
665         return( newDN );
666 }
667
668 void
669 ldap_dnfree( LDAPDN *dn )
670 {
671         int iRDN;
672         
673         if ( dn == NULL ) {
674                 return;
675         }
676
677         for ( iRDN = 0; dn[ iRDN ]; iRDN++ ) {
678                 assert( dn[ iRDN ][ 0 ] );
679
680                 ldap_rdnfree( dn[ iRDN ][ 0 ] );
681         }
682
683         LDAP_VFREE( dn );
684 }
685
686 /*
687  * Converts a string representation of a DN (in LDAPv3, LDAPv2 or DCE)
688  * into a structural representation of the DN, by separating attribute
689  * types and values encoded in the more appropriate form, which is
690  * string or OID for attribute types and binary form of the BER encoded
691  * value or Unicode string. Formats different from LDAPv3 are parsed
692  * according to their own rules and turned into the more appropriate
693  * form according to LDAPv3.
694  *
695  * NOTE: I realize the code is getting spaghettish; it is rather
696  * experimental and will hopefully turn into something more simple
697  * and readable as soon as it works as expected.
698  */
699
700 int
701 ldap_str2dn( const char *str, LDAPDN **dn, unsigned flags )
702 {
703         const char      *p;
704         int             rc = LDAP_INVALID_DN_SYNTAX;
705
706         LDAPDN          *newDN = NULL;
707         LDAPRDN         *newRDN = NULL;
708         
709         assert( str );
710         assert( dn );
711
712         Debug( LDAP_DEBUG_TRACE, "=> ldap_str2dn(%s,%u)\n%s", str, flags, "" );
713
714         *dn = NULL;
715
716         switch ( LDAP_DN_FORMAT( flags ) ) {
717         case LDAP_DN_FORMAT_LDAP:
718         case LDAP_DN_FORMAT_LDAPV3:
719         case LDAP_DN_FORMAT_LDAPV2:
720         case LDAP_DN_FORMAT_DCE:
721                 break;
722
723         /* unsupported in str2dn */
724         case LDAP_DN_FORMAT_UFN:
725         case LDAP_DN_FORMAT_AD_CANONICAL:
726                 return( LDAP_INVALID_DN_SYNTAX );
727
728         default:
729                 return( LDAP_OTHER );
730         }
731
732         if ( str[ 0 ] == '\0' ) {
733                 return( LDAP_SUCCESS );
734         }
735
736         p = str;
737         if ( LDAP_DN_DCE( flags ) ) {
738                 
739                 /* 
740                  * (from Luke Howard: thnx) A RDN separator is required
741                  * at the beginning of an (absolute) DN.
742                  */
743                 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
744                         goto parsing_error;
745                 }
746                 p++;
747                 
748         } else if ( LDAP_DN_LDAP( flags ) ) {
749                 /*
750                  * if dn starts with '/' let's make it a DCE dn
751                  */
752                 if ( LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
753                         flags |= LDAP_DN_FORMAT_DCE;
754                         p++;
755                 }
756         }
757
758         for ( ; p[ 0 ]; p++ ) {
759                 LDAPDN          *dn;
760                 int             err;
761                 
762                 err = ldap_str2rdn( p, &newRDN, &p, flags );
763                 if ( err != LDAP_SUCCESS ) {
764                         goto parsing_error;
765                 }
766
767                 /* 
768                  * We expect a rdn separator
769                  */
770                 if ( p[ 0 ] ) {
771                         switch ( LDAP_DN_FORMAT( flags ) ) {
772                         case LDAP_DN_FORMAT_LDAPV3:
773                                 if ( !LDAP_DN_RDN_SEP( p[ 0 ] ) ) {
774                                         rc = LDAP_OTHER;
775                                         goto parsing_error;
776                                 }
777                                 break;
778         
779                         case LDAP_DN_FORMAT_LDAP:
780                         case LDAP_DN_FORMAT_LDAPV2:
781                                 if ( !LDAP_DN_RDN_SEP_V2( p[ 0 ] ) ) {
782                                         rc = LDAP_OTHER;
783                                         goto parsing_error;
784                                 }
785                                 break;
786         
787                         case LDAP_DN_FORMAT_DCE:
788                                 if ( !LDAP_DN_RDN_SEP_DCE( p[ 0 ] ) ) {
789                                         rc = LDAP_OTHER;
790                                         goto parsing_error;
791                                 }
792                                 break;
793                         }
794                 }
795
796
797                 if ( LDAP_DN_DCE( flags ) ) {
798                         /* add in reversed order */
799                         dn = ldapava_insert_into_dn( newDN, newRDN, 0 );
800                 } else {
801                         dn = ldapava_append_to_dn( newDN, newRDN );
802                 }
803
804                 if ( dn == NULL ) {
805                         rc = LDAP_NO_MEMORY;
806                         goto parsing_error;
807                 }
808
809                 newDN = dn;
810                 newRDN = NULL;
811                                 
812                 if ( p[ 0 ] == '\0' ) {
813                                         
814                         /* 
815                          * the DN is over, phew
816                          */
817                         rc = LDAP_SUCCESS;
818                         goto return_result;
819                 }
820         }
821         
822 parsing_error:;
823         if ( newRDN ) {
824                 ldap_rdnfree( newRDN );
825         }
826
827         if ( newDN ) {
828                 ldap_dnfree( newDN );
829                 newDN = NULL;
830         }
831
832 return_result:;
833
834         Debug( LDAP_DEBUG_TRACE, "<= ldap_str2dn(%s,%u)=%d\n", str, flags, rc );
835         *dn = newDN;
836         
837         return( rc );
838 }
839
840 /*
841  * ldap_str2rdn
842  *
843  * Parses a relative DN according to flags up to a rdn separator 
844  * or to the end of str.
845  * Returns the rdn and a pointer to the string continuation, which
846  * corresponds to the rdn separator or to '\0' in case the string is over.
847  */
848 int
849 ldap_str2rdn( const char *str, LDAPRDN **rdn, const char **n, unsigned flags )
850 {
851         const char      *p;
852         int             state = B4AVA;
853         int             rc = LDAP_INVALID_DN_SYNTAX;
854         int             attrTypeEncoding = LDAP_AVA_STRING, 
855                         attrValueEncoding = LDAP_AVA_STRING;
856
857         struct berval   *attrType = NULL;
858         struct berval   *attrValue = NULL;
859
860         LDAPRDN         *newRDN = NULL;
861         
862         assert( str );
863         assert( rdn );
864         assert( n );
865
866         Debug( LDAP_DEBUG_TRACE, "=> ldap_str2rdn(%s,%u)\n%s", str, flags, "" );
867
868         *rdn = NULL;
869         *n = NULL;
870
871         switch ( LDAP_DN_FORMAT( flags ) ) {
872         case LDAP_DN_FORMAT_LDAP:
873         case LDAP_DN_FORMAT_LDAPV3:
874         case LDAP_DN_FORMAT_LDAPV2:
875         case LDAP_DN_FORMAT_DCE:
876                 break;
877
878         /* unsupported in str2dn */
879         case LDAP_DN_FORMAT_UFN:
880         case LDAP_DN_FORMAT_AD_CANONICAL:
881                 return( LDAP_INVALID_DN_SYNTAX );
882
883         default:
884                 return( LDAP_OTHER );
885         }
886
887         if ( str[ 0 ] == '\0' ) {
888                 return( LDAP_SUCCESS );
889         }
890
891         p = str;
892         for ( ; p[ 0 ] || state == GOTAVA; ) {
893                 
894                 /*
895                  * The parser in principle advances one token a time,
896                  * or toggles state if preferable.
897                  */
898                 switch (state) {
899
900                 /*
901                  * an AttributeType can be encoded as:
902                  * - its string representation; in detail, implementations
903                  *   MUST recognize AttributeType string type names listed 
904                  *   in section 2.3 of draft-ietf-ldapbis-dn-XX.txt, and
905                  *   MAY recognize other names.
906                  * - its numeric OID (a dotted decimal string); in detail
907                  *   RFC 2253 asserts that ``Implementations MUST allow 
908                  *   an oid in the attribute type to be prefixed by one 
909                  *   of the character strings "oid." or "OID."''.  As soon
910                  *   as draft-ietf-ldapbis-dn-XX.txt obsoletes RFC 2253 
911                  *   I'm not sure whether this is required or not any 
912                  *   longer; to be liberal, we still implement it.
913                  */
914                 case B4AVA:
915                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
916                                 if ( !LDAP_DN_ALLOW_ONE_SPACE( flags ) ) {
917                                         /* error */
918                                         goto parsing_error;
919                                 }
920                                 p++;
921                         }
922
923                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
924                                 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
925                                         /* error */
926                                         goto parsing_error;
927                                 }
928
929                                 /* whitespace is allowed (and trimmed) */
930                                 p++;
931                                 while ( p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
932                                         p++;
933                                 }
934
935                                 if ( !p[ 0 ] ) {
936                                         /* error: we expected an AVA */
937                                         goto parsing_error;
938                                 }
939                         }
940
941                         /* oid */
942                         if ( LDAP_DN_OID_LEADCHAR( p[ 0 ] ) ) {
943                                 state = B4OIDATTRTYPE;
944                                 break;
945                         }
946                         
947                         /* else must be alpha */
948                         if ( !LDAP_DN_DESC_LEADCHAR( p[ 0 ] ) ) {
949                                 goto parsing_error;
950                         }
951                         
952                         /* LDAPv2 "oid." prefix */
953                         if ( LDAP_DN_LDAPV2( flags ) ) {
954                                 /*
955                                  * to be overly pedantic, we only accept
956                                  * "OID." or "oid."
957                                  */
958                                 if ( flags & LDAP_DN_PEDANTIC ) {
959                                         if ( !strncmp( p, "OID.", 4 )
960                                                 || !strncmp( p, "oid.", 4 ) ) {
961                                                 p += 4;
962                                                 state = B4OIDATTRTYPE;
963                                                 break;
964                                         }
965                                 } else {
966                                        if ( !strncasecmp( p, "oid.", 4 ) ) {
967                                                p += 4;
968                                                state = B4OIDATTRTYPE;
969                                                break;
970                                        }
971                                 }
972                         }
973
974                         state = B4STRINGATTRTYPE;
975                         break;
976                 
977                 case B4OIDATTRTYPE: {
978                         int             err = LDAP_SUCCESS;
979                         char            *type;
980                         
981                         type = parse_numericoid( &p, &err, 0 );
982                         if ( type == NULL ) {
983                                 goto parsing_error;
984                         }
985                         attrType = LDAP_MALLOC( sizeof( struct berval ) );
986                         if ( attrType== NULL ) {
987                                 rc = LDAP_NO_MEMORY;
988                                 goto parsing_error;
989                         }
990                         attrType->bv_val = type;
991                         attrType->bv_len = strlen( type );
992                         attrTypeEncoding = LDAP_AVA_BINARY;
993
994                         state = B4AVAEQUALS;
995                         break;
996                 }
997
998                 case B4STRINGATTRTYPE: {
999                         const char      *startPos, *endPos = NULL;
1000                         ber_len_t       len;
1001                         
1002                         /* 
1003                          * the starting char has been found to be
1004                          * a LDAP_DN_DESC_LEADCHAR so we don't re-check it
1005                          * FIXME: DCE attr types seem to have a more
1006                          * restrictive syntax (no '-' ...) 
1007                          */
1008                         for ( startPos = p++; p[ 0 ]; p++ ) {
1009                                 if ( LDAP_DN_DESC_CHAR( p[ 0 ] ) ) {
1010                                         continue;
1011                                 }
1012
1013                                 if ( LDAP_DN_LANG_SEP( p[ 0 ] ) ) {
1014                                         
1015                                         /*
1016                                          * RFC 2253 does not explicitly
1017                                          * allow lang extensions to attribute 
1018                                          * types in DNs ... 
1019                                          */
1020                                         if ( flags & LDAP_DN_PEDANTIC ) {
1021                                                 goto parsing_error;
1022                                         }
1023
1024                                         /*
1025                                          * we trim ';' and following lang 
1026                                          * and so from attribute types
1027                                          */
1028                                         endPos = p;
1029                                         for ( ; LDAP_DN_ATTRDESC_CHAR( p[ 0 ] )
1030                                                         || LDAP_DN_LANG_SEP( p[ 0 ] ); p++ ) {
1031                                                 /* no op */ ;
1032                                         }
1033                                         break;
1034                                 }
1035                                 break;
1036                         }
1037
1038                         len = ( endPos ? endPos : p ) - startPos;
1039                         if ( len == 0 ) {
1040                                 goto parsing_error;
1041                         }
1042                         
1043                         assert( attrType == NULL );
1044                         attrType = LDAP_MALLOC( sizeof( struct berval ) );
1045                         if ( attrType == NULL ) {
1046                                 rc = LDAP_NO_MEMORY;
1047                                 goto parsing_error;
1048                         }
1049                         attrType->bv_val = LDAP_STRNDUP( startPos, len );
1050                         if ( attrType->bv_val == NULL ) {
1051                                 rc = LDAP_NO_MEMORY;
1052                                 goto parsing_error;
1053                         }
1054                         attrType->bv_len = len;
1055                         attrTypeEncoding = LDAP_AVA_STRING;
1056
1057                         /*
1058                          * here we need to decide whether to use it as is 
1059                          * or turn it in OID form; as a consequence, we
1060                          * need to decide whether to binary encode the value
1061                          */
1062                         
1063                         state = B4AVAEQUALS;
1064                         break;
1065                 }
1066                                 
1067                 case B4AVAEQUALS:
1068                         /* spaces may not be allowed */
1069                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1070                                 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1071                                         goto parsing_error;
1072                                 }
1073                         
1074                                 /* trim spaces */
1075                                 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1076                                         /* no op */
1077                                 }
1078                         }
1079
1080                         /* need equal sign */
1081                         if ( !LDAP_DN_AVA_EQUALS( p[ 0 ] ) ) {
1082                                 goto parsing_error;
1083                         }
1084                         p++;
1085
1086                         /* spaces may not be allowed */
1087                         if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1088                                 if ( !LDAP_DN_ALLOW_SPACES( flags ) ) {
1089                                         goto parsing_error;
1090                                 }
1091
1092                                 /* trim spaces */
1093                                 for ( p++; LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1094                                         /* no op */
1095                                 }
1096                         }
1097
1098                         /*
1099                          * octothorpe means a BER encoded value will follow
1100                          * FIXME: I don't think DCE will allow it
1101                          */
1102                         if ( LDAP_DN_OCTOTHORPE( p[ 0 ] ) ) {
1103                                 p++;
1104                                 attrValueEncoding = LDAP_AVA_BINARY;
1105                                 state = B4BINARYVALUE;
1106                                 break;
1107                         }
1108
1109                         /* STRING value expected */
1110
1111                         /* 
1112                          * if we're pedantic, an attribute type in OID form
1113                          * SHOULD imply a BER encoded attribute value; we
1114                          * should at least issue a warning
1115                          */
1116                         if ( ( flags & LDAP_DN_PEDANTIC )
1117                                 && ( attrTypeEncoding == LDAP_AVA_BINARY ) ) {
1118                                 /* OID attrType SHOULD use binary encoding */
1119                                 goto parsing_error;
1120                         }
1121
1122                         attrValueEncoding = LDAP_AVA_STRING;
1123
1124                         /* 
1125                          * LDAPv2 allows the attribute value to be quoted;
1126                          * also, IA5 values are expected, in principle
1127                          */
1128                         if ( LDAP_DN_LDAPV2( flags ) || LDAP_DN_LDAP( flags ) ) {
1129                                 if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1130                                         p++;
1131                                         state = B4IA5VALUEQUOTED;
1132                                         break;
1133                                 }
1134
1135                                 if ( LDAP_DN_LDAPV2( flags ) ) {
1136                                         state = B4IA5VALUE;
1137                                         break;
1138                                 }
1139                         }
1140
1141                         /*
1142                          * here STRING means RFC 2253 string
1143                          * FIXME: what about DCE strings? 
1144                          */
1145                         state = B4STRINGVALUE;
1146                         break;
1147
1148                 case B4BINARYVALUE:
1149                         if ( hexstr2binval( p, &attrValue, &p, flags ) ) {
1150                                 goto parsing_error;
1151                         }
1152
1153                         state = GOTAVA;
1154                         break;
1155
1156                 case B4STRINGVALUE:
1157                         switch ( LDAP_DN_FORMAT( flags ) ) {
1158                         case LDAP_DN_FORMAT_LDAP:
1159                         case LDAP_DN_FORMAT_LDAPV3:
1160                                 if ( str2strval( p, &attrValue, &p, flags, 
1161                                                         &attrValueEncoding ) ) {
1162                                         goto parsing_error;
1163                                 }
1164                                 break;
1165
1166                         case LDAP_DN_FORMAT_DCE:
1167                                 if ( DCE2strval( p, &attrValue, &p, flags ) ) {
1168                                         goto parsing_error;
1169                                 }
1170                                 break;
1171
1172                         default:
1173                                 assert( 0 );
1174                         }
1175
1176                         state = GOTAVA;
1177                         break;
1178
1179                 case B4IA5VALUE:
1180                         if ( IA52strval( p, &attrValue, &p, flags ) ) {
1181                                 goto parsing_error;
1182                         }
1183
1184                         state = GOTAVA;
1185                         break;
1186                 
1187                 case B4IA5VALUEQUOTED:
1188
1189                         /* lead quote already stripped */
1190                         if ( quotedIA52strval( p, &attrValue, 
1191                                                 &p, flags ) ) {
1192                                 goto parsing_error;
1193                         }
1194
1195                         state = GOTAVA;
1196                         break;
1197
1198                 case GOTAVA: {
1199                         LDAPAVA *ava;
1200                         LDAPRDN *rdn;
1201                         int     rdnsep = 0;
1202
1203                         /*
1204                          * we accept empty values
1205                          */
1206                         ava = ldapava_new( attrType, attrValue, 
1207                                         attrValueEncoding );
1208                         if ( ava == NULL ) {
1209                                 rc = LDAP_NO_MEMORY;
1210                                 goto parsing_error;
1211                         }
1212
1213                         rdn = ldapava_append_to_rdn( newRDN, ava );
1214                         if ( rdn == NULL ) {
1215                                 rc = LDAP_NO_MEMORY;
1216                                 goto parsing_error;
1217                         }
1218                         newRDN = rdn;
1219                         
1220                         /* 
1221                          * if we got an AVA separator ('+', or ',' for DCE ) 
1222                          * we expect a new AVA for this RDN; otherwise 
1223                          * we add the RDN to the DN
1224                          */
1225                         switch ( LDAP_DN_FORMAT( flags ) ) {
1226                         case LDAP_DN_FORMAT_LDAP:
1227                         case LDAP_DN_FORMAT_LDAPV3:
1228                         case LDAP_DN_FORMAT_LDAPV2:
1229                                 if ( !LDAP_DN_AVA_SEP( p[ 0 ] ) ) {
1230                                         rdnsep = 1;
1231                                 }
1232                                 break;
1233
1234                         case LDAP_DN_FORMAT_DCE:
1235                                 if ( !LDAP_DN_AVA_SEP_DCE( p[ 0 ] ) ) {
1236                                         rdnsep = 1;
1237                                 }
1238                                 break;
1239                         }
1240
1241                         if ( rdnsep ) {
1242                                 /* 
1243                                  * the RDN is over, phew
1244                                  */
1245                                 *n = p;
1246                                 rc = LDAP_SUCCESS;
1247                                 goto return_result;
1248                         }
1249
1250                         /* they should have been used in an AVA */
1251                         attrType = NULL;
1252                         attrValue = NULL;
1253                         
1254                         p++;
1255                         state = B4AVA;
1256                         break;
1257                 }
1258
1259                 default:
1260                         assert( 0 );
1261                         goto parsing_error;
1262                 }
1263         }
1264         
1265 parsing_error:;
1266         /* They are set to NULL after they're used in an AVA */
1267         if ( attrType ) {
1268                 ber_bvfree( attrType );
1269         }
1270
1271         if ( attrValue ) {
1272                 ber_bvfree( attrValue );
1273         }
1274
1275         if ( newRDN ) {
1276                 ldap_rdnfree( newRDN );
1277                 newRDN = NULL;
1278         }
1279
1280 return_result:;
1281
1282         Debug( LDAP_DEBUG_TRACE, "<= ldap_str2rdn(%*s)=%d\n", 
1283                         *n - p, str, rc );
1284         *rdn = newRDN;
1285         
1286         return( rc );
1287 }
1288
1289 /*
1290  * reads in a UTF-8 string value, unescaping stuff:
1291  * '\' + LDAP_DN_NEEDESCAPE(c) -> 'c'
1292  * '\' + HEXPAIR(p) -> unhex(p)
1293  */
1294 static int
1295 str2strval( const char *str, struct berval **val, const char **next, unsigned flags, unsigned *retFlags )
1296 {
1297         const char      *p, *startPos, *endPos = NULL;
1298         ber_len_t       len, escapes, unescapes;
1299
1300         assert( str );
1301         assert( val );
1302         assert( next );
1303
1304         *val = NULL;
1305         *next = NULL;
1306
1307         for ( startPos = p = str, escapes = 0, unescapes = 0; p[ 0 ]; p++ ) {
1308                 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1309                         p++;
1310                         if ( p[ 0 ] == '\0' ) {
1311                                 return( 1 );
1312                         }
1313                         if ( ( p == startPos + 1 && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1314                                         || ( LDAP_DN_VALUE_END( p[ 1 ] ) && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) )
1315                                         || LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1316                                 escapes++;
1317                                 continue;
1318                         }
1319
1320                         if ( LDAP_DN_HEXPAIR( p ) ) {
1321                                 char c;
1322
1323                                 hexstr2bin( p, &c );
1324                                 escapes += 2;
1325
1326                                 if ( !LDAP_DN_ASCII_PRINTABLE( c ) ) {
1327
1328                                         /*
1329                                          * we assume the string is UTF-8
1330                                          */
1331                                         *retFlags = LDAP_AVA_NONPRINTABLE;
1332                                 }
1333                                 p++;
1334
1335                                 continue;
1336                         }
1337
1338                         if ( LDAP_DN_PEDANTIC & flags ) {
1339                                 return( 1 );
1340                         }
1341                         /* 
1342                          * FIXME: we allow escaping 
1343                          * of chars that don't need 
1344                          * to and do not belong to 
1345                          * HEXDIGITS (we also allow
1346                          * single hexdigit; maybe we 
1347                          * shouldn't).
1348                          */
1349                         unescapes++;
1350
1351                 } else if ( ( LDAP_DN_LDAP( flags ) && LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) 
1352                                 || ( LDAP_DN_LDAPV3( flags ) && LDAP_DN_VALUE_END( p[ 0 ] ) ) ) {
1353                         break;
1354
1355                 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) ) {
1356                         /* 
1357                          * FIXME: maybe we can add 
1358                          * escapes if not pedantic?
1359                          */
1360                         return( 1 );
1361                 }
1362         }
1363
1364         /*
1365          * we do allow unescaped spaces at the end
1366          * of the value only in non-pedantic mode
1367          */
1368         if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1369                         !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1370                 if ( flags & LDAP_DN_PEDANTIC ) {
1371                         return( 1 );
1372                 }
1373
1374                 /* strip trailing (unescaped) spaces */
1375                 for ( endPos = p - 1; 
1376                                 endPos > startPos + 1 && 
1377                                 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1378                                 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1379                                 endPos-- ) {
1380                         /* no op */
1381                 }
1382         }
1383
1384         /*
1385          * FIXME: test memory?
1386          */
1387         len = ( endPos ? endPos : p ) - startPos - escapes - unescapes;
1388         *val = LDAP_MALLOC( sizeof( struct berval ) );
1389         ( *val )->bv_len = len;
1390
1391         if ( escapes == 0 && unescapes == 0 ) {
1392                 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1393
1394         } else {
1395                 ber_len_t       s, d;
1396
1397                 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1398                 for ( s = 0, d = 0; d < len; ) {
1399                         if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1400                                 s++;
1401                                 if ( ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( startPos[ s ] ) )
1402                                                 || ( s == len - 1 && LDAP_DN_NEEDESCAPE_TRAIL( startPos[ s ] ) )
1403                                                 || LDAP_DN_NEEDESCAPE( startPos[ s ] ) ) {
1404                                         ( *val )->bv_val[ d++ ] = 
1405                                                 startPos[ s++ ];
1406                                         
1407                                 } else if ( LDAP_DN_HEXPAIR( &startPos[ s ] ) ) {
1408                                         char    c;
1409
1410                                         hexstr2bin( &startPos[ s ], &c );
1411                                         ( *val )->bv_val[ d++ ] = c;
1412                                         s += 2;
1413                                         
1414                                 } else {
1415                                         /*
1416                                          * we allow escaping of chars
1417                                          * that do not need to 
1418                                          */
1419                                         ( *val )->bv_val[ d++ ] = 
1420                                                 startPos[ s++ ];
1421                                 }
1422
1423                         } else {
1424                                 ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1425                         }
1426                 }
1427
1428                 ( *val )->bv_val[ d ] = '\0';
1429                 assert( strlen( ( *val )->bv_val ) == len );
1430         }
1431
1432
1433         *next = p;
1434
1435         return( 0 );
1436 }
1437
1438 static int
1439 DCE2strval( const char *str, struct berval **val, const char **next, unsigned flags )
1440 {
1441         const char      *p, *startPos, *endPos = NULL;
1442         ber_len_t       len, escapes;
1443
1444         assert( str );
1445         assert( val );
1446         assert( next );
1447
1448         *val = NULL;
1449         *next = NULL;
1450         
1451         for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1452                 if ( LDAP_DN_ESCAPE_DCE( p[ 0 ] ) ) {
1453                         p++;
1454                         if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
1455                                 escapes++;
1456
1457                         } else {
1458                                 return( 1 );
1459                         }
1460
1461                 } else if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1462                         break;
1463                 }
1464
1465                 /*
1466                  * FIXME: can we accept anything else? I guess we need
1467                  * to stop if a value is not legal
1468                  */
1469         }
1470
1471         /* 
1472          * (unescaped) trailing spaces are trimmed must be silently ignored;
1473          * so we eat them
1474          */
1475         if ( p > startPos + 1 && LDAP_DN_ASCII_SPACE( p[ -1 ] ) &&
1476                         !LDAP_DN_ESCAPE( p[ -2 ] ) ) {
1477                 if ( flags & LDAP_DN_PEDANTIC ) {
1478                         return( 1 );
1479                 }
1480
1481                 /* strip trailing (unescaped) spaces */
1482                 for ( endPos = p - 1; 
1483                                 endPos > startPos + 1 && 
1484                                 LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1485                                 !LDAP_DN_ESCAPE( endPos[ -2 ] );
1486                                 endPos-- ) {
1487                         /* no op */
1488                 }
1489         }
1490
1491
1492         len = ( endPos ? endPos : p ) - startPos - escapes;
1493         *val = LDAP_MALLOC( sizeof( struct berval ) );
1494         ( *val )->bv_len = len;
1495         if ( escapes == 0 ){
1496                 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1497
1498         } else {
1499                 ber_len_t       s, d;
1500
1501                 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1502                 for ( s = 0, d = 0; d < len; ) {
1503                         /*
1504                          * This point is reached only if escapes 
1505                          * are properly used, so all we need to
1506                          * do is eat them
1507                          */
1508                         if (  LDAP_DN_ESCAPE_DCE( startPos[ s ] ) ) {
1509                                 s++;
1510
1511                         }
1512                         ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1513                 }
1514                 ( *val )->bv_val[ d ] = '\0';
1515                 assert( strlen( ( *val )->bv_val ) == len );
1516         }
1517         
1518         *next = p;
1519         
1520         return( 0 );
1521 }
1522
1523 static int
1524 IA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1525 {
1526         const char      *p, *startPos, *endPos = NULL;
1527         ber_len_t       len, escapes;
1528
1529         assert( str );
1530         assert( val );
1531         assert( next );
1532
1533         *val = NULL;
1534         *next = NULL;
1535
1536         /*
1537          * LDAPv2 (RFC 1779)
1538          */
1539         
1540         for ( startPos = p = str, escapes = 0; p[ 0 ]; p++ ) {
1541                 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1542                         p++;
1543                         if ( p[ 0 ] == '\0' ) {
1544                                 return( 1 );
1545                         }
1546
1547                         if ( !LDAP_DN_NEEDESCAPE( p[ 0 ] )
1548                                         && ( LDAP_DN_PEDANTIC & flags ) ) {
1549                                 return( 1 );
1550                         }
1551                         escapes++;
1552
1553                 } else if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1554                         break;
1555                 }
1556
1557                 /*
1558                  * FIXME: can we accept anything else? I guess we need
1559                  * to stop if a value is not legal
1560                  */
1561         }
1562
1563         /* strip trailing (unescaped) spaces */
1564         for ( endPos = p; 
1565                         endPos > startPos + 1 && 
1566                         LDAP_DN_ASCII_SPACE( endPos[ -1 ] ) &&
1567                         !LDAP_DN_ESCAPE( endPos[ -2 ] );
1568                         endPos-- ) {
1569                 /* no op */
1570         }
1571
1572         *val = LDAP_MALLOC( sizeof( struct berval ) );
1573         len = ( endPos ? endPos : p ) - startPos - escapes;
1574         ( *val )->bv_len = len;
1575         if ( escapes == 0 ) {
1576                 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1577
1578         } else {
1579                 ber_len_t       s, d;
1580                 
1581                 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1582                 for ( s = 0, d = 0; d < len; ) {
1583                         if ( LDAP_DN_ESCAPE( startPos[ s ] ) ) {
1584                                 s++;
1585                         }
1586                         ( *val )->bv_val[ d++ ] = startPos[ s++ ];
1587                 }
1588                 ( *val )->bv_val[ d ] = '\0';
1589                 assert( strlen( ( *val )->bv_val ) == len );
1590         }
1591         *next = p;
1592
1593         return( 0 );
1594 }
1595
1596 static int
1597 quotedIA52strval( const char *str, struct berval **val, const char **next, unsigned flags )
1598 {
1599         const char      *p, *startPos, *endPos = NULL;
1600         ber_len_t       len;
1601         unsigned        escapes = 0;
1602
1603         assert( str );
1604         assert( val );
1605         assert( next );
1606
1607         *val = NULL;
1608         *next = NULL;
1609
1610         /* initial quote already eaten */
1611         for ( startPos = p = str; p[ 0 ]; p++ ) {
1612                 /* 
1613                  * According to RFC 1779, the quoted value can
1614                  * contain escaped as well as unescaped special values;
1615                  * as a consequence we tolerate escaped values 
1616                  * (e.g. '"\,"' -> '\,') and escape unescaped specials
1617                  * (e.g. '","' -> '\,').
1618                  */
1619                 if ( LDAP_DN_ESCAPE( p[ 0 ] ) ) {
1620                         if ( p[ 1 ] == '\0' ) {
1621                                 return( 1 );
1622                         }
1623                         p++;
1624
1625                         if ( !LDAP_DN_V2_PAIR( p[ 0 ] )
1626                                         && ( LDAP_DN_PEDANTIC & flags ) ) {
1627                                 /*
1628                                  * do we allow to escape normal chars?
1629                                  * LDAPv2 does not allow any mechanism 
1630                                  * for escaping chars with '\' and hex 
1631                                  * pair
1632                                  */
1633                                 return( 1 );
1634                         }
1635                         escapes++;
1636
1637                 } else if ( LDAP_DN_QUOTES( p[ 0 ] ) ) {
1638                         endPos = p;
1639                         /* eat closing quotes */
1640                         p++;
1641                         break;
1642                 }
1643
1644                 /*
1645                  * FIXME: can we accept anything else? I guess we need
1646                  * to stop if a value is not legal
1647                  */
1648         }
1649
1650         if ( endPos == NULL ) {
1651                 return( 1 );
1652         }
1653
1654         /* Strip trailing (unescaped) spaces */
1655         for ( ; p[ 0 ] && LDAP_DN_ASCII_SPACE( p[ 0 ] ); p++ ) {
1656                 /* no op */
1657         }
1658
1659         len = endPos - startPos - escapes;
1660         assert( len >= 0 );
1661         *val = LDAP_MALLOC( sizeof( struct berval ) );
1662         ( *val )->bv_len = len;
1663         if ( escapes == 0 ) {
1664                 ( *val )->bv_val = LDAP_STRNDUP( startPos, len );
1665
1666         } else {
1667                 ber_len_t       s, d;
1668                 
1669                 ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1670                 ( *val )->bv_len = len;
1671
1672                 for ( s = d = 0; d < len; ) {
1673                         if ( LDAP_DN_ESCAPE( str[ s ] ) ) {
1674                                 s++;
1675                         }
1676                         ( *val )->bv_val[ d++ ] = str[ s++ ];
1677                 }
1678                 ( *val )->bv_val[ d ] = '\0';
1679                 assert( strlen( ( *val )->bv_val ) == len );
1680         }
1681
1682         *next = p;
1683
1684         return( 0 );
1685 }
1686
1687 static int
1688 hexstr2bin( const char *str, char *c )
1689 {
1690         char    c1, c2;
1691
1692         assert( str );
1693         assert( c );
1694
1695         c1 = str[ 0 ];
1696         c2 = str[ 1 ];
1697
1698         if ( LDAP_DN_ASCII_DIGIT( c1 ) ) {
1699                 *c = c1 - '0';
1700
1701         } else {
1702                 c1 = tolower( c1 );
1703
1704                 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c1 ) ) {
1705                         *c = c1 - 'a' + 10;
1706                 }
1707         }
1708
1709         *c <<= 4;
1710
1711         if ( LDAP_DN_ASCII_DIGIT( c2 ) ) {
1712                 *c += c2 - '0';
1713                 
1714         } else {
1715                 c2 = tolower( c2 );
1716
1717                 if ( LDAP_DN_ASCII_LCASE_HEXALPHA( c2 ) ) {
1718                         *c += c2 - 'a' + 10;
1719                 }
1720         }
1721
1722         return( 0 );
1723 }
1724
1725 static int
1726 hexstr2binval( const char *str, struct berval **val, const char **next, unsigned flags )
1727 {
1728         const char      *p, *startPos, *endPos = NULL;
1729         ber_len_t       len;
1730         ber_len_t       s, d;
1731
1732         assert( str );
1733         assert( val );
1734         assert( next );
1735
1736         *val = NULL;
1737         *next = NULL;
1738
1739         for ( startPos = p = str; p[ 0 ]; p += 2 ) {
1740                 switch ( LDAP_DN_FORMAT( flags ) ) {
1741                 case LDAP_DN_FORMAT_LDAPV3:
1742                         if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1743                                 goto end_of_value;
1744                         }
1745                         break;
1746
1747                 case LDAP_DN_FORMAT_LDAP:
1748                 case LDAP_DN_FORMAT_LDAPV2:
1749                         if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1750                                 goto end_of_value;
1751                         }
1752                         break;
1753
1754                 case LDAP_DN_FORMAT_DCE:
1755                         if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1756                                 goto end_of_value;
1757                         }
1758                         break;
1759                 }
1760
1761                 if ( LDAP_DN_ASCII_SPACE( p[ 0 ] ) ) {
1762                         if ( flags & LDAP_DN_PEDANTIC ) {
1763                                 return( 1 );
1764                         }
1765                         endPos = p;
1766
1767                         for ( ; p[ 0 ]; p++ ) {
1768                                 switch ( LDAP_DN_FORMAT( flags ) ) {
1769                                 case LDAP_DN_FORMAT_LDAPV3:
1770                                         if ( LDAP_DN_VALUE_END( p[ 0 ] ) ) {
1771                                                 goto end_of_value;
1772                                         }
1773                                         break;
1774
1775                                 case LDAP_DN_FORMAT_LDAP:
1776                                 case LDAP_DN_FORMAT_LDAPV2:
1777                                         if ( LDAP_DN_VALUE_END_V2( p[ 0 ] ) ) {
1778                                                 goto end_of_value;
1779                                         }
1780                                         break;
1781
1782                                 case LDAP_DN_FORMAT_DCE:
1783                                         if ( LDAP_DN_VALUE_END_DCE( p[ 0 ] ) ) {
1784                                                 goto end_of_value;
1785                                         }
1786                                         break;
1787                                 }
1788                         }
1789                         break;
1790                 }
1791                 
1792                 if ( !LDAP_DN_HEXPAIR( p ) ) {
1793                         return( 1 );
1794                 }
1795         }
1796
1797 end_of_value:;
1798
1799         len = ( ( endPos ? endPos : p ) - startPos ) / 2;
1800         /* must be even! */
1801         assert( 2 * len == (ber_len_t) (( endPos ? endPos : p ) - startPos ));
1802
1803         *val = LDAP_MALLOC( sizeof( struct berval ) );
1804         if ( *val == NULL ) {
1805                 return( LDAP_NO_MEMORY );
1806         }
1807
1808         ( *val )->bv_len = len;
1809         ( *val )->bv_val = LDAP_MALLOC( len + 1 );
1810         if ( ( *val )->bv_val == NULL ) {
1811                 LDAP_FREE( *val );
1812                 return( LDAP_NO_MEMORY );
1813         }
1814
1815         for ( s = 0, d = 0; d < len; s += 2, d++ ) {
1816                 char    c;
1817
1818                 hexstr2bin( &startPos[ s ], &c );
1819
1820                 ( *val )->bv_val[ d ] = c;
1821         }
1822
1823         ( *val )->bv_val[ d ] = '\0';
1824         *next = p;
1825
1826         return( 0 );
1827 }
1828
1829 /*
1830  * convert a byte in a hexadecimal pair
1831  */
1832 static int
1833 byte2hexpair( const char *val, char *pair )
1834 {
1835         static const char       hexdig[] = "0123456789abcdef";
1836
1837         assert( val );
1838         assert( pair );
1839
1840         /* 
1841          * we assume the string has enough room for the hex encoding
1842          * of the value
1843          */
1844
1845         pair[ 0 ] = hexdig[ 0x0f & ( val[ 0 ] >> 4 ) ];
1846         pair[ 1 ] = hexdig[ 0x0f & val[ 0 ] ];
1847         
1848         return( 0 );
1849 }
1850
1851 /*
1852  * convert a binary value in hexadecimal pairs
1853  */
1854 static int
1855 binval2hexstr( struct berval *val, char *str )
1856 {
1857         ber_len_t       s, d;
1858
1859         assert( val );
1860         assert( str );
1861
1862         if ( val->bv_len == 0 ) {
1863                 return( 0 );
1864         }
1865
1866         /* 
1867          * we assume the string has enough room for the hex encoding
1868          * of the value
1869          */
1870
1871         for ( s = 0, d = 0; s < val->bv_len; s++, d += 2 ) {
1872                 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1873         }
1874         
1875         return( 0 );
1876 }
1877
1878 /*
1879  * Length of the string representation, accounting for escaped hex
1880  * of UTF-8 chars
1881  */
1882 static int
1883 strval2strlen( struct berval *val, unsigned flags, ber_len_t *len )
1884 {
1885         ber_len_t       l, cl = 1;
1886         char            *p;
1887         int             escaped_byte_len = LDAP_DN_IS_PRETTY( flags ) ? 1 : 3;
1888         
1889         assert( val );
1890         assert( len );
1891
1892         *len = 0;
1893         if ( val->bv_len == 0 ) {
1894                 return( 0 );
1895         }
1896
1897         for ( l = 0, p = val->bv_val; p[ 0 ]; p += cl ) {
1898                 cl = ldap_utf8_charlen( p );
1899                 if ( cl == 0 ) {
1900                         /* illegal utf-8 char! */
1901                         return( -1 );
1902
1903                 } else if ( cl > 1 ) {
1904                         ber_len_t cnt;
1905
1906                         for ( cnt = 1; cnt < cl; cnt++ ) {
1907                                 if ( ( p[ cnt ] & 0x80 ) == 0x00 ) {
1908                                         return( -1 );
1909                                 }
1910                         }
1911                         l += escaped_byte_len * cl;
1912                 
1913                 /* 
1914                  * there might be some chars we want to escape in form
1915                  * of a couple of hexdigits for optimization purposes
1916                  */
1917                 } else if ( LDAP_DN_WILLESCAPE( flags, p[ 0 ] ) ) {
1918                         l += 3;
1919
1920                 } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
1921                                 || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
1922                                 || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
1923                         l += 2;
1924
1925                 } else {
1926                         l++;
1927                 }
1928         }
1929
1930         *len = l;
1931
1932         return( 0 );
1933 }
1934
1935 /*
1936  * convert to string representation, escaping with hex the UTF-8 stuff;
1937  * assume the destination has enough room for escaping
1938  */
1939 static int
1940 strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
1941 {
1942         ber_len_t       s, d, end;
1943
1944         assert( val );
1945         assert( str );
1946         assert( len );
1947
1948         if ( val->bv_len == 0 ) {
1949                 *len = 0;
1950                 return( 0 );
1951         }
1952
1953         /* 
1954          * we assume the string has enough room for the hex encoding
1955          * of the value
1956          */
1957         for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
1958                 ber_len_t       cl = ldap_utf8_charlen( &val->bv_val[ s ] );
1959                 
1960                 /* 
1961                  * there might be some chars we want to escape in form
1962                  * of a couple of hexdigits for optimization purposes
1963                  */
1964                 if ( ( cl > 1 && !LDAP_DN_IS_PRETTY( flags ) ) 
1965                                 || LDAP_DN_WILLESCAPE( flags, val->bv_val[ s ] ) ) {
1966                         for ( ; cl--; ) {
1967                                 str[ d++ ] = '\\';
1968                                 byte2hexpair( &val->bv_val[ s ], &str[ d ] );
1969                                 s++;
1970                                 d += 2;
1971                         }
1972
1973                 } else if ( cl > 1 ) {
1974                         for ( ; cl--; ) {
1975                                 str[ d++ ] = val->bv_val[ s++ ];
1976                         }
1977
1978                 } else {
1979                         if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
1980                                         || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
1981                                         || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
1982                                 str[ d++ ] = '\\';
1983                         }
1984                         str[ d++ ] = val->bv_val[ s++ ];
1985                 }
1986         }
1987
1988         *len = d;
1989         
1990         return( 0 );
1991 }
1992
1993 /*
1994  * Length of the IA5 string representation (no UTF-8 allowed)
1995  */
1996 static int
1997 strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len )
1998 {
1999         ber_len_t       l;
2000         char            *p;
2001
2002         assert( val );
2003         assert( len );
2004
2005         *len = 0;
2006         if ( val->bv_len == 0 ) {
2007                 return( 0 );
2008         }
2009
2010         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2011                 /*
2012                  * Turn value into a binary encoded BER
2013                  */
2014                 return( -1 );
2015
2016         } else {
2017                 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2018                         if ( LDAP_DN_NEEDESCAPE( p[ 0 ] )
2019                                         || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) )
2020                                         || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) {
2021                                 l += 2;
2022
2023                         } else {
2024                                 l++;
2025                         }
2026                 }
2027         }
2028
2029         *len = l;
2030         
2031         return( 0 );
2032 }
2033
2034 /*
2035  * convert to string representation (np UTF-8)
2036  * assume the destination has enough room for escaping
2037  */
2038 static int
2039 strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2040 {
2041         ber_len_t       s, d, end;
2042
2043         assert( val );
2044         assert( str );
2045         assert( len );
2046
2047         if ( val->bv_len == 0 ) {
2048                 *len = 0;
2049                 return( 0 );
2050         }
2051
2052         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2053                 /*
2054                  * Turn value into a binary encoded BER
2055                  */
2056                 *len = 0;
2057                 return( -1 );
2058
2059         } else {
2060                 /* 
2061                  * we assume the string has enough room for the hex encoding
2062                  * of the value
2063                  */
2064
2065                 for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) {
2066                         if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] )
2067                                         || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) )
2068                                         || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) {
2069                                 str[ d++ ] = '\\';
2070                         }
2071                         str[ d++ ] = val->bv_val[ s++ ];
2072                 }
2073         }
2074
2075         *len = d;
2076         
2077         return( 0 );
2078 }
2079
2080 /*
2081  * Length of the (supposedly) DCE string representation, 
2082  * accounting for escaped hex of UTF-8 chars
2083  */
2084 static int
2085 strval2DCEstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2086 {
2087         ber_len_t       l;
2088         char            *p;
2089
2090         assert( val );
2091         assert( len );
2092
2093         *len = 0;
2094         if ( val->bv_len == 0 ) {
2095                 return( 0 );
2096         }
2097
2098         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2099                 /* 
2100                  * FIXME: Turn the value into a binary encoded BER?
2101                  */
2102                 return( -1 );
2103                 
2104         } else {
2105                 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2106                         if ( LDAP_DN_NEEDESCAPE_DCE( p[ 0 ] ) ) {
2107                                 l += 2;
2108
2109                         } else {
2110                                 l++;
2111                         }
2112                 }
2113         }
2114
2115         *len = l;
2116
2117         return( 0 );
2118 }
2119
2120 /*
2121  * convert to (supposedly) DCE string representation, 
2122  * escaping with hex the UTF-8 stuff;
2123  * assume the destination has enough room for escaping
2124  */
2125 static int
2126 strval2DCEstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2127 {
2128         ber_len_t       s, d;
2129
2130         assert( val );
2131         assert( str );
2132         assert( len );
2133
2134         if ( val->bv_len == 0 ) {
2135                 *len = 0;
2136                 return( 0 );
2137         }
2138
2139         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2140                 /*
2141                  * FIXME: Turn the value into a binary encoded BER?
2142                  */
2143                 *len = 0;
2144                 return( -1 );
2145                 
2146         } else {
2147
2148                 /* 
2149                  * we assume the string has enough room for the hex encoding
2150                  * of the value
2151                  */
2152
2153                 for ( s = 0, d = 0; s < val->bv_len; ) {
2154                         if ( LDAP_DN_NEEDESCAPE_DCE( val->bv_val[ s ] ) ) {
2155                                 str[ d++ ] = '\\';
2156                         }
2157                         str[ d++ ] = val->bv_val[ s++ ];
2158                 }
2159         }
2160
2161         *len = d;
2162         
2163         return( 0 );
2164 }
2165
2166 /*
2167  * Length of the (supposedly) AD canonical string representation, 
2168  * accounting for escaped hex of UTF-8 chars
2169  */
2170 static int
2171 strval2ADstrlen( struct berval *val, unsigned flags, ber_len_t *len )
2172 {
2173         ber_len_t       l;
2174         char            *p;
2175
2176         assert( val );
2177         assert( len );
2178
2179         *len = 0;
2180         if ( val->bv_len == 0 ) {
2181                 return( 0 );
2182         }
2183
2184         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2185                 /* 
2186                  * FIXME: Turn the value into a binary encoded BER?
2187                  */
2188                 return( -1 );
2189                 
2190         } else {
2191                 for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) {
2192                         if ( LDAP_DN_NEEDESCAPE_AD( p[ 0 ] ) ) {
2193                                 l += 2;
2194
2195                         } else {
2196                                 l++;
2197                         }
2198                 }
2199         }
2200
2201         *len = l;
2202         
2203         return( 0 );
2204 }
2205
2206 /*
2207  * convert to (supposedly) AD string representation, 
2208  * escaping with hex the UTF-8 stuff;
2209  * assume the destination has enough room for escaping
2210  */
2211 static int
2212 strval2ADstr( struct berval *val, char *str, unsigned flags, ber_len_t *len )
2213 {
2214         ber_len_t       s, d;
2215
2216         assert( val );
2217         assert( str );
2218         assert( len );
2219
2220         if ( val->bv_len == 0 ) {
2221                 *len = 0;
2222                 return( 0 );
2223         }
2224
2225         if ( flags & LDAP_AVA_NONPRINTABLE ) {
2226                 /*
2227                  * FIXME: Turn the value into a binary encoded BER?
2228                  */
2229                 *len = 0;
2230                 return( -1 );
2231                 
2232         } else {
2233
2234                 /* 
2235                  * we assume the string has enough room for the hex encoding
2236                  * of the value
2237                  */
2238
2239                 for ( s = 0, d = 0; s < val->bv_len; ) {
2240                         if ( LDAP_DN_NEEDESCAPE_AD( val->bv_val[ s ] ) ) {
2241                                 str[ d++ ] = '\\';
2242                         }
2243                         str[ d++ ] = val->bv_val[ s++ ];
2244                 }
2245         }
2246
2247         *len = d;
2248         
2249         return( 0 );
2250 }
2251
2252 /*
2253  * If the DN is terminated by single-AVA RDNs with attribute type of "dc",
2254  * the forst part of the AD representation of the DN is written in DNS
2255  * form, i.e. dot separated domain name components (as suggested 
2256  * by Luke Howard, http://www.padl.com/~lukeh)
2257  */
2258 static int
2259 dn2domain( LDAPDN *dn, char *str, int *iRDN )
2260 {
2261         int             i;
2262         int             domain = 0, first = 1;
2263         ber_len_t       l = 1; /* we move the null also */
2264
2265         /* we are guaranteed there's enough memory in str */
2266
2267         /* sanity */
2268         assert( dn );
2269         assert( str );
2270         assert( iRDN );
2271         assert( *iRDN > 0 );
2272
2273         for ( i = *iRDN; i >= 0; i-- ) {
2274                 LDAPRDN         *rdn;
2275                 LDAPAVA         *ava;
2276
2277                 assert( dn[ i ][ 0 ] );
2278                 rdn = dn[ i ][ 0 ];
2279
2280                 assert( rdn[ 0 ][ 0 ] );
2281                 ava = rdn[ 0 ][ 0 ];
2282
2283                 if ( !LDAP_DN_IS_RDN_DC( rdn ) ) {
2284                         break;
2285                 }
2286
2287                 domain = 1;
2288                 
2289                 if ( first ) {
2290                         first = 0;
2291                         AC_MEMCPY( str, ava->la_value->bv_val, 
2292                                         ava->la_value->bv_len + 1);
2293                         l += ava->la_value->bv_len;
2294
2295                 } else {
2296                         AC_MEMCPY( str + ava->la_value->bv_len + 1, str, l);
2297                         AC_MEMCPY( str, ava->la_value->bv_val, 
2298                                         ava->la_value->bv_len );
2299                         str[ ava->la_value->bv_len ] = '.';
2300                         l += ava->la_value->bv_len + 1;
2301                 }
2302         }
2303
2304         *iRDN = i;
2305
2306         return( domain );
2307 }
2308
2309 static int
2310 rdn2strlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len,
2311          int ( *s2l )( struct berval *v, unsigned f, ber_len_t *l ) )
2312 {
2313         int             iAVA;
2314         ber_len_t       l = 0;
2315
2316         *len = 0;
2317
2318         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2319                 LDAPAVA         *ava = rdn[ iAVA ][ 0 ];
2320
2321                 /* len(type) + '=' + '+' | ',' */
2322                 l += ava->la_attr->bv_len + 2;
2323
2324                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2325                         /* octothorpe + twice the length */
2326                         l += 1 + 2 * ava->la_value->bv_len;
2327
2328                 } else {
2329                         ber_len_t       vl;
2330                         unsigned        f = flags | ava->la_flags;
2331                         
2332                         if ( ( *s2l )( ava->la_value, f, &vl ) ) {
2333                                 return( -1 );
2334                         }
2335                         l += vl;
2336                 }
2337         }
2338         
2339         *len = l;
2340         
2341         return( 0 );
2342 }
2343
2344 static int
2345 rdn2str( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len,
2346         int ( *s2s ) ( struct berval *v, char * s, unsigned f, ber_len_t *l ) )
2347 {
2348         int             iAVA;
2349         ber_len_t       l = 0;
2350
2351         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2352                 LDAPAVA         *ava = rdn[ iAVA ][ 0 ];
2353
2354                 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val, 
2355                                 ava->la_attr->bv_len );
2356                 l += ava->la_attr->bv_len;
2357
2358                 str[ l++ ] = '=';
2359
2360                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2361                         str[ l++ ] = '#';
2362                         if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2363                                 return( -1 );
2364                         }
2365                         l += 2 * ava->la_value->bv_len;
2366
2367                 } else {
2368                         ber_len_t       vl;
2369                         unsigned        f = flags | ava->la_flags;
2370
2371                         if ( ( *s2s )( ava->la_value, &str[ l ], f, &vl ) ) {
2372                                 return( -1 );
2373                         }
2374                         l += vl;
2375                 }
2376                 str[ l++ ] = ( rdn[ iAVA + 1 ] ? '+' : ',' );
2377         }
2378
2379         *len = l;
2380
2381         return( 0 );
2382 }
2383
2384 static int
2385 rdn2DCEstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2386 {
2387         int             iAVA;
2388         ber_len_t       l = 0;
2389
2390         *len = 0;
2391
2392         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2393                 LDAPAVA         *ava = rdn[ iAVA ][ 0 ];
2394
2395                 /* len(type) + '=' + ',' | '/' */
2396                 l += ava->la_attr->bv_len + 2;
2397
2398                 switch ( ava->la_flags ) {
2399                 case LDAP_AVA_BINARY:
2400                         /* octothorpe + twice the length */
2401                         l += 1 + 2 * ava->la_value->bv_len;
2402                         break;
2403
2404                 case LDAP_AVA_STRING: {
2405                         ber_len_t       vl;
2406                         unsigned        f = flags | ava->la_flags;
2407                         
2408                         if ( strval2DCEstrlen( ava->la_value, f, &vl ) ) {
2409                                 return( -1 );
2410                         }
2411                         l += vl;
2412                         break;
2413                 }
2414
2415                 default:
2416                         return( -1 );
2417                 }
2418         }
2419         
2420         *len = l;
2421         
2422         return( 0 );
2423 }
2424
2425 static int
2426 rdn2DCEstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2427 {
2428         int             iAVA;
2429         ber_len_t       l = 0;
2430
2431         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2432                 LDAPAVA         *ava = rdn[ iAVA ][ 0 ];
2433
2434                 if ( first ) {
2435                         first = 0;
2436                 } else {
2437                         str[ l++ ] = ( iAVA ? ',' : '/' );
2438                 }
2439
2440                 AC_MEMCPY( &str[ l ], ava->la_attr->bv_val, 
2441                                 ava->la_attr->bv_len );
2442                 l += ava->la_attr->bv_len;
2443
2444                 str[ l++ ] = '=';
2445
2446                 switch ( ava->la_flags ) {
2447                         case LDAP_AVA_BINARY:
2448                         str[ l++ ] = '#';
2449                         if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2450                                 return( -1 );
2451                         }
2452                         l += 2 * ava->la_value->bv_len;
2453                         break;
2454
2455                 case LDAP_AVA_STRING: {
2456                         ber_len_t       vl;
2457                         unsigned        f = flags | ava->la_flags;
2458
2459                         if ( strval2DCEstr( ava->la_value, &str[ l ], f, &vl ) ) {
2460                                 return( -1 );
2461                         }
2462                         l += vl;
2463                         break;
2464                 }
2465                                       
2466                 default:
2467                         return( -1 );
2468                 }
2469         }
2470
2471         *len = l;
2472
2473         return( 0 );
2474 }
2475
2476 static int
2477 rdn2UFNstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2478 {
2479         int             iAVA;
2480         ber_len_t       l = 0;
2481
2482         assert( rdn );
2483         assert( len );
2484
2485         *len = 0;
2486
2487         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2488                 LDAPAVA         *ava = rdn[ iAVA ][ 0 ];
2489
2490                 /* ' + ' | ', ' */
2491                 l += ( rdn[ iAVA + 1 ] ? 3 : 2 );
2492
2493                 /* FIXME: are binary values allowed in UFN? */
2494                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2495                         /* octothorpe + twice the value */
2496                         l += 1 + 2 * ava->la_value->bv_len;
2497
2498                 } else {
2499                         ber_len_t       vl;
2500                         unsigned        f = flags | ava->la_flags;
2501
2502                         if ( strval2strlen( ava->la_value, f, &vl ) ) {
2503                                 return( -1 );
2504                         }
2505                         l += vl;
2506                 }
2507         }
2508         
2509         *len = l;
2510         
2511         return( 0 );
2512 }
2513
2514 static int
2515 rdn2UFNstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len )
2516 {
2517         int             iAVA;
2518         ber_len_t       l = 0;
2519
2520         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2521                 LDAPAVA         *ava = rdn[ iAVA ][ 0 ];
2522
2523                 if ( ava->la_flags & LDAP_AVA_BINARY ) {
2524                         str[ l++ ] = '#';
2525                         if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2526                                 return( -1 );
2527                         }
2528                         l += 2 * ava->la_value->bv_len;
2529                         
2530                 } else {
2531                         ber_len_t       vl;
2532                         unsigned        f = flags | ava->la_flags;
2533                         
2534                         if ( strval2str( ava->la_value, &str[ l ], f, &vl ) ) {
2535                                 return( -1 );
2536                         }
2537                         l += vl;
2538                 }
2539
2540                 if ( rdn[ iAVA + 1 ]) {
2541                         AC_MEMCPY( &str[ l ], " + ", 3 );
2542                         l += 3;
2543
2544                 } else {
2545                         AC_MEMCPY( &str[ l ], ", ", 2 );
2546                         l += 2;
2547                 }
2548         }
2549
2550         *len = l;
2551
2552         return( 0 );
2553 }
2554
2555 static int
2556 rdn2ADstrlen( LDAPRDN *rdn, unsigned flags, ber_len_t *len )
2557 {
2558         int             iAVA;
2559         ber_len_t       l = 0;
2560
2561         assert( rdn );
2562         assert( len );
2563
2564         *len = 0;
2565
2566         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2567                 LDAPAVA         *ava = rdn[ iAVA ][ 0 ];
2568
2569                 /* ',' | '/' */
2570                 l++;
2571
2572                 /* FIXME: are binary values allowed in UFN? */
2573                 switch ( ava->la_flags ) {
2574                 case LDAP_AVA_BINARY:
2575                         /* octothorpe + twice the value */
2576                         l += 1 + 2 * ava->la_value->bv_len;
2577                         break;
2578
2579                 case LDAP_AVA_STRING: {
2580                         ber_len_t       vl;
2581                         unsigned        f = flags | ava->la_flags;
2582
2583                         if ( strval2ADstrlen( ava->la_value, f, &vl ) ) {
2584                                 return( -1 );
2585                         }
2586                         l += vl;
2587                         break;
2588                 }
2589
2590                 default:
2591                         return( -1 );
2592                 }
2593         }
2594         
2595         *len = l;
2596         
2597         return( 0 );
2598 }
2599
2600 static int
2601 rdn2ADstr( LDAPRDN *rdn, char *str, unsigned flags, ber_len_t *len, int first )
2602 {
2603         int             iAVA;
2604         ber_len_t       l = 0;
2605
2606         for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
2607                 LDAPAVA         *ava = rdn[ iAVA ][ 0 ];
2608
2609                 if ( first ) {
2610                         first = 0;
2611                 } else {
2612                         str[ l++ ] = ( iAVA ? ',' : '/' );
2613                 }
2614
2615                 switch ( ava->la_flags ) {
2616                 case LDAP_AVA_BINARY:
2617                         str[ l++ ] = '#';
2618                         if ( binval2hexstr( ava->la_value, &str[ l ] ) ) {
2619                                 return( -1 );
2620                         }
2621                         l += 2 * ava->la_value->bv_len;
2622                         break;
2623                         
2624                 case LDAP_AVA_STRING: {
2625                         ber_len_t       vl;
2626                         unsigned        f = flags | ava->la_flags;
2627                         
2628                         if ( strval2ADstr( ava->la_value, &str[ l ], f, &vl ) ) {
2629                                 return( -1 );
2630                         }
2631                         l += vl;
2632                         break;
2633                 }
2634
2635                 default:
2636                         return( -1 );
2637                 }
2638         }
2639
2640         *len = l;
2641
2642         return( 0 );
2643 }
2644
2645 /*
2646  * ldap_rdn2str
2647  *
2648  * Returns in str a string representation of rdn based on flags.
2649  * There is some duplication of code between this and ldap_dn2str;
2650  * this is wanted to reduce the allocation of temporary buffers.
2651  */
2652 int
2653 ldap_rdn2str( LDAPRDN *rdn, char **str, unsigned flags )
2654 {
2655         int             rc, back;
2656         ber_len_t       l;
2657         
2658         assert( str );
2659
2660         if ( rdn == NULL ) {
2661                 *str = LDAP_STRDUP( "" );
2662                 return( LDAP_SUCCESS );
2663         }
2664
2665         /*
2666          * This routine wastes "back" bytes at the end of the string
2667          */
2668
2669         *str = NULL;
2670         switch ( LDAP_DN_FORMAT( flags ) ) {
2671         case LDAP_DN_FORMAT_LDAPV3:
2672                 if ( rdn2strlen( rdn, flags, &l, strval2strlen ) ) {
2673                         return( LDAP_OTHER );
2674                 }
2675                 break;
2676
2677         case LDAP_DN_FORMAT_LDAPV2:
2678                 if ( rdn2strlen( rdn, flags, &l, strval2IA5strlen ) ) {
2679                         return( LDAP_OTHER );
2680                 }
2681                 break;
2682
2683         case LDAP_DN_FORMAT_UFN:
2684                 if ( rdn2UFNstrlen( rdn, flags, &l ) ) {
2685                         return( LDAP_OTHER );
2686                 }
2687                 break;
2688
2689         case LDAP_DN_FORMAT_DCE:
2690                 if ( rdn2DCEstrlen( rdn, flags, &l ) ) {
2691                         return( LDAP_OTHER );
2692                 }
2693                 break;
2694
2695         case LDAP_DN_FORMAT_AD_CANONICAL:
2696                 if ( rdn2ADstrlen( rdn, flags, &l ) ) {
2697                         return( LDAP_OTHER );
2698                 }
2699                 break;
2700
2701         default:
2702                 return( LDAP_INVALID_DN_SYNTAX );
2703         }
2704
2705         *str = LDAP_MALLOC( l + 1 );
2706
2707         switch ( LDAP_DN_FORMAT( flags ) ) {
2708         case LDAP_DN_FORMAT_LDAPV3:
2709                 rc = rdn2str( rdn, *str, flags, &l, strval2str );
2710                 back = 1;
2711                 break;
2712
2713         case LDAP_DN_FORMAT_LDAPV2:
2714                 rc = rdn2str( rdn, *str, flags, &l, strval2IA5str );
2715                 back = 1;
2716                 break;
2717
2718         case LDAP_DN_FORMAT_UFN:
2719                 rc = rdn2UFNstr( rdn, *str, flags, &l );
2720                 back = 2;
2721                 break;
2722
2723         case LDAP_DN_FORMAT_DCE:
2724                 rc = rdn2DCEstr( rdn, *str, flags, &l, 1 );
2725                 back = 0;
2726                 break;
2727
2728         case LDAP_DN_FORMAT_AD_CANONICAL:
2729                 rc = rdn2ADstr( rdn, *str, flags, &l, 1 );
2730                 back = 0;
2731                 break;
2732
2733         default:
2734                 /* need at least one of the previous */
2735                 return( LDAP_OTHER );
2736         }
2737
2738         if ( rc ) {
2739                 ldap_memfree( *str );
2740                 return( LDAP_OTHER );
2741         }
2742
2743         ( *str )[ l - back ] = '\0';
2744
2745         return( LDAP_SUCCESS );
2746 }
2747
2748 /*
2749  * Very bulk implementation; many optimizations can be performed
2750  *   - a NULL dn results in an empty string ""
2751  * 
2752  * FIXME: doubts
2753  *   a) what do we do if a UTF-8 string must be converted in LDAPv2?
2754  *      we must encode it in binary form ('#' + HEXPAIRs)
2755  *   b) does DCE/AD support UTF-8?
2756  *      no clue; don't think so.
2757  *   c) what do we do when binary values must be converted in UTF/DCE/AD?
2758  *      use binary encoded BER
2759  */ 
2760 int ldap_dn2str( LDAPDN *dn, char **str, unsigned flags )
2761 {
2762         int             iRDN;
2763         int             rc = LDAP_OTHER;
2764         ber_len_t       len, l;
2765
2766         /* stringifying helpers for LDAPv3/LDAPv2 */
2767         int ( *sv2l ) ( struct berval *v, unsigned f, ber_len_t *l );
2768         int ( *sv2s ) ( struct berval *v, char *s, unsigned f, ber_len_t *l );
2769
2770         assert( str );
2771
2772         Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2str(%u)\n%s%s", flags, "", "" );
2773
2774         *str = NULL;
2775
2776         /* 
2777          * a null dn means an empty dn string 
2778          * FIXME: better raise an error?
2779          */
2780         if ( dn == NULL ) {
2781                 *str = LDAP_STRDUP( "" );
2782                 return( LDAP_SUCCESS );
2783         }
2784
2785         switch ( LDAP_DN_FORMAT( flags ) ) {
2786         case LDAP_DN_FORMAT_LDAPV3:
2787                 sv2l = strval2strlen;
2788                 sv2s = strval2str;
2789                 goto got_funcs;
2790
2791         case LDAP_DN_FORMAT_LDAPV2:
2792                 sv2l = strval2IA5strlen;
2793                 sv2s = strval2IA5str;
2794 got_funcs:
2795                 
2796                 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2797                         ber_len_t       rdnl;
2798                         LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
2799                         
2800                         if ( rdn2strlen( rdn, flags, &rdnl, sv2l ) ) {
2801                                 goto return_results;
2802                         }
2803
2804                         len += rdnl;
2805                 }
2806
2807                 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2808                         rc = LDAP_NO_MEMORY;
2809                         break;
2810                 }
2811
2812                 for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
2813                         ber_len_t       rdnl;
2814                         LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
2815                         
2816                         if ( rdn2str( rdn, &( *str )[ l ], flags, 
2817                                         &rdnl, sv2s ) ) {
2818                                 LDAP_FREE( *str );
2819                                 *str = NULL;
2820                                 goto return_results;
2821                         }
2822                         l += rdnl;
2823                 }
2824
2825                 assert( l == len );
2826
2827                 /* 
2828                  * trim the last ',' (the allocated memory 
2829                  * is one byte longer than required)
2830                  */
2831                 ( *str )[ len - 1 ] = '\0';
2832
2833                 rc = LDAP_SUCCESS;
2834                 break;
2835
2836         case LDAP_DN_FORMAT_UFN: {
2837
2838                 /*
2839                  * FIXME: quoting from RFC 1781:
2840                  *
2841    To take a distinguished name, and generate a name of this format with
2842    attribute types omitted, the following steps are followed.
2843
2844     1.  If the first attribute is of type CommonName, the type may be
2845         omitted.
2846
2847     2.  If the last attribute is of type Country, the type may be
2848         omitted.
2849
2850     3.  If the last attribute is of type Country, the last
2851         Organisation attribute may have the type omitted.
2852
2853     4.  All attributes of type OrganisationalUnit may have the type
2854         omitted, unless they are after an Organisation attribute or
2855         the first attribute is of type OrganisationalUnit.
2856
2857          * this should be the pedantic implementation.
2858                  *
2859                  * Here the standard implementation reflects
2860                  * the one historically provided by OpenLDAP
2861                  * (and UMIch, I presume), with the variant
2862                  * of spaces and plusses (' + ') separating 
2863                  * rdn components.
2864                  * 
2865                  * A non-standard but nice implementation could
2866                  * be to turn the  final "dc" attributes into a 
2867                  * dot-separated domain.
2868                  *
2869                  * Other improvements could involve the use of
2870                  * friendly country names and so.
2871                  */
2872 #ifdef DC_IN_UFN
2873                 int     leftmost_dc = -1;
2874                 int     last_iRDN = -1;
2875 #endif /* DC_IN_UFN */
2876
2877                 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2878                         ber_len_t       rdnl;
2879                         LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
2880                         
2881                         if ( rdn2UFNstrlen( rdn, flags, &rdnl ) ) {
2882                                 goto return_results;
2883                         }
2884                         len += rdnl;
2885
2886 #ifdef DC_IN_UFN
2887                         if ( LDAP_DN_IS_RDN_DC( rdn ) ) {
2888                                 if ( leftmost_dc == -1 ) {
2889                                         leftmost_dc = iRDN;
2890                                 }
2891                         } else {
2892                                 leftmost_dc = -1;
2893                         }
2894 #endif /* DC_IN_UFN */
2895                 }
2896
2897                 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2898                         rc = LDAP_NO_MEMORY;
2899                         break;
2900                 }
2901
2902 #ifdef DC_IN_UFN
2903                 if ( leftmost_dc == -1 ) {
2904 #endif /* DC_IN_UFN */
2905                         for ( l = 0, iRDN = 0; dn[ iRDN ]; iRDN++ ) {
2906                                 ber_len_t       vl;
2907                                 LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
2908                         
2909                                 if ( rdn2UFNstr( rdn, &( *str )[ l ], 
2910                                                 flags, &vl ) ) {
2911                                         LDAP_FREE( *str );
2912                                         *str = NULL;
2913                                         goto return_results;
2914                                 }
2915                                 l += vl;
2916                         }
2917
2918                         /* 
2919                          * trim the last ', ' (the allocated memory 
2920                          * is two bytes longer than required)
2921                          */
2922                         ( *str )[ len - 2 ] = '\0';
2923 #ifdef DC_IN_UFN
2924                 } else {
2925                         last_iRDN = iRDN - 1;
2926
2927                         for ( l = 0, iRDN = 0; iRDN < leftmost_dc; iRDN++ ) {
2928                                 ber_len_t       vl;
2929                                 LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
2930                         
2931                                 if ( rdn2UFNstr( rdn, &( *str )[ l ], 
2932                                                 flags, &vl ) ) {
2933                                         LDAP_FREE( *str );
2934                                         *str = NULL;
2935                                         goto return_results;
2936                                 }
2937                                 l += vl;
2938                         }
2939
2940                         if ( !dn2domain( dn, &( *str )[ l ], &last_iRDN ) ) {
2941                                 LDAP_FREE( *str );
2942                                 *str = NULL;
2943                                 goto return_results;
2944                         }
2945
2946                         /* the string is correctly terminated by dn2domain */
2947                 }
2948 #endif /* DC_IN_UFN */
2949                 
2950                 rc = LDAP_SUCCESS;
2951                 break;
2952         }
2953
2954         case LDAP_DN_FORMAT_DCE:
2955
2956                 for ( iRDN = 0, len = 0; dn[ iRDN ]; iRDN++ ) {
2957                         ber_len_t       rdnl;
2958                         LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
2959                         
2960                         if ( rdn2DCEstrlen( rdn, flags, &rdnl ) ) {
2961                                 goto return_results;
2962                         }
2963
2964                         len += rdnl;
2965                 }
2966
2967                 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
2968                         rc = LDAP_NO_MEMORY;
2969                         break;
2970                 }
2971
2972                 for ( l = 0; iRDN--; ) {
2973                         ber_len_t       rdnl;
2974                         LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
2975                         
2976                         if ( rdn2DCEstr( rdn, &( *str )[ l ], flags, 
2977                                         &rdnl, 0 ) ) {
2978                                 LDAP_FREE( *str );
2979                                 *str = NULL;
2980                                 goto return_results;
2981                         }
2982                         l += rdnl;
2983                 }
2984
2985                 assert( l == len );
2986
2987                 ( *str )[ len ] = '\0';
2988
2989                 rc = LDAP_SUCCESS;
2990                 break;
2991
2992         case LDAP_DN_FORMAT_AD_CANONICAL: {
2993                 
2994                 /*
2995                  * Sort of UFN for DCE DNs: a slash ('/') separated
2996                  * global->local DN with no types; strictly speaking,
2997                  * the naming context should be a domain, which is
2998                  * written in DNS-style, e.g. dot-deparated.
2999                  * 
3000                  * Example:
3001                  * 
3002                  *      "givenName=Bill+sn=Gates,ou=People,dc=microsoft,dc=com"
3003                  *
3004                  * will read
3005                  * 
3006                  *      "microsoft.com/People/Bill,Gates"
3007                  */ 
3008                 for ( iRDN = 0, len = -1; dn[ iRDN ]; iRDN++ ) {
3009                         ber_len_t       rdnl;
3010                         LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
3011                         
3012                         if ( rdn2ADstrlen( rdn, flags, &rdnl ) ) {
3013                                 goto return_results;
3014                         }
3015
3016                         len += rdnl;
3017                 }
3018
3019                 if ( ( *str = LDAP_MALLOC( len + 1 ) ) == NULL ) {
3020                         rc = LDAP_NO_MEMORY;
3021                         break;
3022                 }
3023
3024                 iRDN--;
3025                 if ( iRDN && dn2domain( dn, *str, &iRDN ) ) {
3026                         for ( l = strlen( *str ); iRDN >= 0 ; iRDN-- ) {
3027                                 ber_len_t       rdnl;
3028                                 LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
3029                         
3030                                 if ( rdn2ADstr( rdn, &( *str )[ l ], 
3031                                                 flags, &rdnl, 0 ) ) {
3032                                         LDAP_FREE( *str );
3033                                         *str = NULL;
3034                                         goto return_results;
3035                                 }
3036                                 l += rdnl;
3037                         }
3038
3039                 } else {
3040                         int             first = 1;
3041
3042                         /*
3043                          * Strictly speaking, AD canonical requires
3044                          * a DN to be in the form "..., dc=smtg",
3045                          * i.e. terminated by a domain component
3046                          */
3047                         if ( flags & LDAP_DN_PEDANTIC ) {
3048                                 LDAP_FREE( *str );
3049                                 *str = NULL;
3050                                 rc = LDAP_INVALID_DN_SYNTAX;
3051                                 break;
3052                         }
3053
3054                         for ( l = 0; iRDN >= 0 ; iRDN-- ) {
3055                                 ber_len_t       rdnl;
3056                                 LDAPRDN         *rdn = dn[ iRDN ][ 0 ];
3057                         
3058                                 if ( rdn2ADstr( rdn, &( *str )[ l ], 
3059                                                 flags, &rdnl, first ) ) {
3060                                         LDAP_FREE( *str );
3061                                         *str = NULL;
3062                                         goto return_results;
3063                                 }
3064                                 if ( first ) {
3065                                         first = 0;
3066                                 }
3067                                 l += rdnl;
3068                         }
3069                 }
3070
3071                 ( *str )[ len ] = '\0';
3072
3073                 rc = LDAP_SUCCESS;
3074                 break;
3075         }
3076
3077         default:
3078                 return( LDAP_INVALID_DN_SYNTAX );
3079
3080         }
3081
3082         Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2str(%s,%u)=%d\n", *str, flags, rc );
3083 return_results:;
3084         return( rc );
3085 }
3086